Почти каждый микроконтроллер имеет на борту универсальный последовательный интерфейс — UART. AVR тут не исключение и поддерживает этот протокол в полном обьеме полностью аппаратно. По структуре это обычный асинхронный последовательный протокол, то есть передающая сторона по очереди выдает в линию 0 и 1, а принимающая отслеживает их и запоминает. Синхронизация идет по времени — приемник и передатчик заранее договариваются о том на какой частоте будет идти обмен. Это очень важный момент! Если скорость передатчика и приемника не будут совпадать, то передачи может не быть вообще, либо будут считаны не те данные.
Протокол
Вначале передатчик бросает линию в низкий уровень — это старт бит. Почуяв что линия просела, приемник выжидает интервал Т1 и считывает первый бит, потом через интервалы Т2 выковыриваются остальные биты. Последний бит это стоп бит. Говорящий о том, что передача этого байта завершена. Это в самом простом случае.
В конце байта, перед стоп битом, может быть и бит четности. Который получается если поксорить между собой все биты, для контроля качества передачи. Также может быть два стопа, опять же для надежности. Битов может быть не 8, а 9. О всех этих параметрах договариваются на берегу, до начала передачи. Самым же популярным является 8 бит, один старт один стоп, без четности.
Причем с самим протоколом можно не заморачиваться — все реализовано аппаратно. Разве что захочется завести второй UART, тогда придется делать его программно.
По такому же протоколу работает COM порт компьютера, разница лишь в разнице напряжений, поэтому именно этот протокол я буду использовать для связи микроконтроллера с компом. Для преобразования напряжений можно использовать RS232-TTL конвертер. Мы же применим встроенный в Pinboard мост USB-UART который образовывает в системе виртуальный COM PORT
Аппаратная часть
Ну тут все просто, соединяем крест-накрест приемник с передатчиком и готово.
Внутри же вначале находится накопительный сдвиговый регистр, в котором происходит сборка байта из битов и регистры данных UDR, куда этот бит передается. Такая структура исключает возможность считать не до конца полученный байт.
Буфер приема состоит из двух байт, что позволяет ему держать два в уме и один еще засасывать в сдвиговый регистр.
Использование UART’a
У AVR есть регистр UDR это UART Data Register (в некоторых контроллерах он может зваться UDR0 или еще как нибудь похоже). На самом деле это два разных регистра, но имеют один адрес. Просто на запись попадает в один (регистр передатчика), а на чтение берет из другого (регистр приемника). Таким образом достаточно просто пихать данные в этот регистр и они улетят приемнику, и, наоборот, считывать их оттуда по приходу.
О том, что байт пришел в регистр UDR нам скажет прерывание по завершению приема, которое вызывается сразу же, как приемник засосет в себя все биты (обычно 8, но может быть и 9, в зависимости от настройки).
Поскольку передача идет довольно медленно, то бездумно пихать данные в регистр UDR нельзя — нужно дождаться окончания передачи предыдущего байта. О том, что UDR пуст и готов к приему нового байта сигнализирует бит UDRE, он же вызовет аппаратное прерывание по опустошению буфера.
Так что постоянно следить за UART вручную не нужно, все обслуживание можно повесить на прерывания и он сам будет все делать. Можно в памяти организовать буфер и туда тупо пихать данные, а на прерывании по опустошению UDR следить за тем есть ли что в буфере и если есть — отправлять.
А по приему, не тупить, а также, по прерыванию, пихать данные в ОЗУ, но уже в буфер приема, откуда их считает уже программа.
Настройка UART
Все настройки приемопередатчика хранятся в регистра конфигурации. Это UCSRA, UCSRB и UCSRС. А скорость задается в паре UBBRH:UBBRL.
Досконально все расписывать не буду — на это есть даташит. Напишу лишь то, что жизненно необходимо.
Регистр UCSRA
Тут нам интересны только биты RXC и TXC это флаги завершения приема и передачи, соответственно. RXC встанет когда непрочитанный байт вылезет в регистр UDR, а TXC встает когда последний стоп-бит прошел, а новое значение в UDR не поступило. Т.е. после прохода всех байтов.
Также одновременно с этими флагами вызывается прерывание (если оно было разрешено). Сбрасываются они аппаратно — принимающий после чтения из регистра UDR, передающий при переходе на прерывание, либо программно (чтобы сбросить флаг программно в него надо записать 1)
Биты UDRE сигнализирует о том, что регистр UDR приемника пуст и в него можно пихать новый байт. Сбрасывается он аппаратно после засылки в UDR какого либо байта. Также генерируется прерывание «Регистр пуст»
Бит U2X — это бит удвоения скорости при работе в ассинхронном режиме. Его надо учитывать при расчете значения в UBBRH:UBBRL
Регистр UCSRB
Тут в первую очередь это биты RXEN и TXEN — разрешение приема и передачи. Стоит их сбросить как выводы UART тут же становятся обычными ножками I/O.
Биты RXCIE, TXCIE, UDRIE разрешают прерывания по завершению приема, передачи и опустошении буфера передачи UDR.
Регистр UCSRC
Самый прикол тут — это бит селектора URSEL дело в том, что по неизвестной причине создаетели решили сэкономить байт адреса и разместили регистры UCSRC и UBRRH в одной адресном пространстве. А как же определять куда записать? А по старшему биту! Поясню на примере. Если мы записываем число у которого седьмой бит равен 1, то оно попадет в UCSRC, а если 0 то UBRRH. Причем этот бит есть не во всех AVR в новых моделях его нет, а регистры имеют разные адреса. Так что надо смотреть в даташите этот момент — есть там бит URSEL или нет.
Остальные биты задают число стопов, наличие и тип контроля четности. Если оставить все по дефолту то будет стандартный режим. Надо только выставить формат посылки. Делается это битами UCSZ0, UCSZ1 и UCSZ2 (этот бит тусуется в регистре UCSRB). Для стандартной 8ми битной посылки туда надо записать две единички.
Скорость обмена.
Тут все зависит от пары UBBRx
Вычисляется требуемое значение по формуле:
UBBR=XTAL/(16*baudrate)-1 для U2X=0
UBBR=XTAL/(8*baudrate)-1 для U2X=1
Где:
XTAL — рабочая тактовая частота контроллера.
baudrate — требуемая скорость (я люблю 9600 :) — чем медленней тем надежней. 9600 в большинстве случаев хватает)
Ошибки передачи
К сожалению мир наш не идеален, поэтому возможны ошибки при приеме. За них отвечают флаги в регистре UCSRA
FE — ошибка кадрирования. Т.е. мы ждали стоп бит, а пришел 0.
OR — переполнение буфера. То есть данные лезут и лезут, а из UDR мы их забирать не успеваем.
PE — не совпал контроль четности.
Примеры кода
Простая приемка и отправка байт. Без использования прерываний.
Для начала инициализация UART в ATMega16 (А таже в Mega8535/8/32 и многих других).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ; Internal Hardware Init ====================================== .equ XTAL = 8000000 .equ baudrate = 9600 .equ bauddivider = XTAL/(16*baudrate)-1 uart_init: LDI R16, low(bauddivider) OUT UBRRL,R16 LDI R16, high(bauddivider) OUT UBRRH,R16 LDI R16,0 OUT UCSRA, R16 ; Прерывания запрещены, прием-передача разрешен. LDI R16, (1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<TXCIE)|(0<<UDRIE) OUT UCSRB, R16 ; Формат кадра - 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор LDI R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1) OUT UCSRC, R16 |
1 2 3 4 5 6 | ; Процедура отправки байта uart_snt: SBIS UCSRA,UDRE ; Пропуск если нет флага готовности RJMP uart_snt ; ждем готовности - флага UDRE OUT UDR, R16 ; шлем байт RET ; Возврат |
1 2 3 4 5 6 7 8 9 | ;Посылка байта: RCALL uart_init ; вызываем нашу процедуру инициализации. Main: LDI R16,'E' ; загоняем в регистр код буквы «E» RCALL uart_snt ; Вызываем процедуру отправки байта. NOP ; Любой дальнейший код NOP NOP |
1 2 3 4 5 6 | ;Ожидание байта uart_rcv: SBIS UCSRA,RXC ; Ждем флага прихода байта RJMP uart_rcv ; вращаясь в цикле IN R16,UDR ; байт пришел - забираем. RET ; Выходим. Результат в R16 |
В главном цикле это выглядит так (я выбросил из главного цикла все что там было для краткости, чтобы в глазах не рябило. Оставил только работу с USART):
1 2 3 4 5 6 7 8 | ; Main ========================================================= Main: RCALL uart_rcv ; Ждем байта INC R16 ; Делаем с ним что-то RCALL uart_snt ; Отправляем обратно. JMP Main |
Если зальешь эту программку в Pinboard и подключишься терминалкой, то на каждый байт контроллер тебе вернет байт следующий по величине. Например на 1 (код 0×31) возвращается 2 (код 0×32). И так далее.
Данный метод прост и работает в лоб. Но имеет одну большую проблему — цикл ожидания прихода байта. В этот момент ничего работать не может. Конечно, можно не зацикливаться наглухо, а просто проверять флаг RxC и крутиться в основном цикле. Но тогда, если передача идет на большой скорости, можно запросто прозевать байт.
Работа на прерываниях
Решение тут одно — использование прерываний хотя бы на прием. А в идеале и на передачу тоже. Сейчас покажу тебе пример буферизированной работы с приемопередатчиком на прерываниях.
Во первых инициализация, она теперь другая — мы разрешаем прерывания:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | ; Internal Hardware Init ====================================== .equ XTAL = 8000000 .equ baudrate = 9600 .equ bauddivider = XTAL/(16*baudrate)-1 uart_init: LDI R16, low(bauddivider) OUT UBRRL,R16 LDI R16, high(bauddivider) OUT UBRRH,R16 LDI R16,0 OUT UCSRA, R16 ; Прерывания разрешены, прием-передача разрешен. LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE) OUT UCSRB, R16 ; Формат кадра - 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор LDI R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1) OUT UCSRC, R16 |
Используем все три прерывания. По приему, по опустошению буфера и по окончании передачи. Но пока разрешаем только два — по приему и по передаче. Иначе при старте мы сразу же ускачем на обработчик UDRIE — буфер то пуст!
В таблицу векторов впишем наши переходы:
1 2 3 4 5 6 | .ORG $016 RJMP RX_OK ; (USART,RXC) USART, Rx Complete .ORG $018 RJMP UD_OK ; (USART,UDRE) USART Data Register Empty .ORG $01A RJMP TX_OK ; (USART,TXC) USART, Tx Complete |
А в секцию обработчиков прерываний добавим нашу процедуру приема:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | RX_OK: PUSHF ; Макрос, пихающий в стек SREG и R16 IN R16,UDR ; Тут главное забрать байт из UDR иначе ; флаг прерывания не снимется ; Дальше, если время позволяет, можно и обработать CPI R16,Value ; Например, разобрать по байтам и выполнить действие BRNE NXT ; Обычным CASE оператором. Action1 ; Делаем что нибудь ценное. Главное не забыть в стеке ; Регистры попрятать. А то будет тебе упячка. NXT: CPI R16,Value2 BRNE RX_Exit Action2 ; Делаем что нибудь ценное2 Rx_Exit: POPF ; Достаем SREG и R16 RETI |
Передача делается побайтно, на вызовах прерываний. Например, надо нам отрыгнуть текстовую строку из флеша:
1 | String: .db "Hello Interrupt Request",0 |
Заводим указатель на эту строку, обычная двубайтная переменная в памяти.
1 2 | .DSEG StrPtr: .data 2 |
Далее, в главной программе, в любом нужном нам месте, загружаем адрес текстовой строки в этот указатель, не забыв умножить его на два. Т.к. компилятор флеш адресует в словах, а контроллер оперирует только байтами:
1 2 3 4 5 6 7 8 9 | Main: NOP ; Любой произвольный код главной программы NOP NOP LDI R17,low(2*String) ; Берем младший байт LDI R18,High(2*String) ; Берем старший байт STS StrPtr,R17 ; Сохраняем Младший байт STS StrPtr+1,R18 ; Сохраняем Сташрий байт |
И сразу же запускаем передачу, путем разрешения прерываний по UDRE. Так как UDR у нас пуст, то прерывание стартует мгновенно.
1 2 3 4 5 6 7 | LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(1<<UDRIE) OUT UCSRB, R16 ;После чего спокойно выполняем любой другой код. NOP NOP NOP |
А дальше все сделает наш обработчик прерывания события UDR Empty. На который ссылается вектор прерывания по опустошению регистра UDR:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | UD_OK: PUSHF ; Макрос, сохраняющий SREG и R16 PUSH ZL ; Сохраняем в стеке Z PUSH ZH LDS ZL,StrPtr ; Грузим указатели в индексные регистры LDS ZH,StrPtr+1 LPM R16,Z+ ; Хватаем байт из флеша. Из нашей строки CPI R16,0 ; Если он не ноль, значит читаем дальше BREQ STOP_RX ; Иначе останавливаем передачу OUT UDR,R16 ; Выдача данных в усарт. STS StrPtr,ZL ; Сохраняем указатель STS StrPtr+1,ZH ; обратно, в память Exit_RX: POP ZH ; Все достаем из стека, выходим. POP ZL POPF RETI ; глушим прерывание по опустошению, выходим из обработчика STOP_RX: LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE) OUT UCSRB, R16 RJMP Exit_RX |
Все, по прерыванию обработчик сам выгребет данные из флеша и сам автоматом себя забанит когда дойдет до нуля в строке.
А зачем нужно прерывание TX_OK? Ну мало ли зачем. Еще какое-нибудь событие повесить. Оно сработает когда произойдет две вещи — UDR кончится и в сдвиговом регистре USART все биты улетят в провод. В принципе, многие юзают его вместо UDRE, но тогда между двумя уходящими байтами будет промежуток периодом в 1 байт. Что не очень кошерно.
Буферизация
Но далеко не всегда можно успеть обработать данные с большой скоростью. В этом случае их приходится куда-то складывать. А передавать/обрабатывать попозже. Особенно это касается отправки. Отправка медленная, а нам бы все сразу в буфер свалить и уйти по своим делам. А USART пускай там постепенно со всем этим разбирается.
Поэтому мы заведем два кольцевых буфера. На прием и на передачу (можно и только на передачу, это чаще требуется). А также ряд служебных переменных:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | ; RAM ======================================================== .DSEG .equ MAXBUFF_IN = 10 ; Размер в байтах .equ MAXBUFF_OUT = 10 IN_buff: .byte MAXBUFF_IN ; Буфер приема IN_PTR_S: .byte 1 ; Указатель начала IN_PTR_E: .byte 1 ; Указатель конца IN_FULL: .byte 1 ; Флаг переполнения OUT_buff: .byte MAXBUFF_OUT ; Буфер передачи OUT_PTR_S: .byte 1 ; Указатель начала OUT_PTR_E: .byte 1 ; Указатель конца OUT_FULL: .byte 1 ; Флаг переполнения. |
Указатели начала показывают откуда мы будем буфер читать, указатель конца нацелен на точку записи. В результате конец убегает, а начало его догоняет. Когда они сравняются — буфер пуст. При достижении максимальных границ буфера (10 байт) указатель переносится в начало, т.к. у нас буфер закольцован.
При этом может быть перехлест указателей между собой. Это даст ошибку переполнения и некорректную работу. Поэтому введены флаги переполнения, возникающие если конец пошел по второму кругу и догнал начало.
Сами указатели я сделал не классическими адресами, а смещениями относительно начала каждого буфера, Так получается оптимальней, не приходится сравнивать двубайтные числа. Но при этом длина буфера ограничена 255 байтами.
Прерывание по приему данных пишет в буфер IN_buff
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | RX_OK: PUSHF ; Макрос, пихающий в стек SREG и R16 PUSH R17 PUSH R18 PUSH XL PUSH XH LDI XL,low(IN_buff) ; Берем адрес начала буффера LDI XH,high(IN_buff) LDS R16,IN_PTR_E ; Берем смещение точки записи LDS R18,IN_PTR_S ; Берем смещение точки чтения ADD XL,R16 ; Сложением адреса со смещением CLR R17 ; получаем адрес точки записи ADC XH,R17 IN R17,UDR ; Забираем данные ST X,R17 ; сохраняем их в кольцо INC R16 ; Увеличиваем смещение CPI R16,MAXBUFF_IN ; Если достигли конца BRNE NoEnd CLR R16 ; переставляем на начало NoEnd: CP R16,R18 ; Дошли до непрочитанных данных? BRNE RX_OUT ; Если нет, то просто выходим RX_FULL: LDI R18,1 ; Если да, то буффер переполнен. STS IN_FULL,R18 ; Записываем флаг наполненности RX_OUT: STS IN_PTR_E,R16 ; Сохраняем смещение. Выходим POP XH POP XL POP R18 POP R17 POPF ; Достаем SREG и R16 RETI |
Если возникнет переполнение, то данные начнут затирать предыдущие, произойдет перехлест указателей, но перед этим поднимется флаг IN_FULL и диспетчер, или кто у нас там будет следить за всякими исключениями, может спешно среагировать и выгрузить буфер.
IN_FULL занимает целый байт, но можно было бы в один бит сделать. Я просто не стал усложнять. При чтении и записи в буфер в фоновой программе надо соблюдать атомарность, т.е. запрещать возможность записи в буфер из прерывания. А то будет трудно уловимый косяк.
Чтение из буфера приема делается тоже просто:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | ; Read from loop Buffer ; IN: NONE ; OUT: R17 - Data, ; R19 - ERROR CODE Buff_Pop: CLI ; Запрещаем прерыания. ; Но лучше запретить прерывания конкретно от ; UART, чем запрещать вообще все. LDI XL,low(IN_buff) ; Берем адрес начала буффера LDI XH,high(IN_buff) LDS R16,IN_PTR_E ; Берем смещение точки записи LDS R18,IN_PTR_S ; Берем смещение точки чтения LDS R19,IN_FULL ; Берм флаг переполнения CPI R19,1 ; Если буффер переполнен, то указатель начала BREQ NeedPop ; Равен указателю конца. Это надо учесть. CP R18,R16 ; Указатель чтения достиг указателя записи? BRNE NeedPop ; Нет! Буффер не пуст. Работаем дальше LDI R19,1 ; Код ошибки - пустой буффер! RJMP _TX_OUT ; Выходим NeedPop: CLR R17 ; Получаем ноль STS IN_FULL,R17 ; Сбрасываем флаг переполнения ADD XL,R18 ; Сложением адреса со смещением ADC XH,R17 ; получаем адрес точки чтения LD R17,X ; Берем байт из буффера CLR R19 ; Сброс кода ошибки INC R18 ; Увеличиваем смещение указателя чтения CPI R18,MAXBUFF_OUT ; Достигли конца кольца? BRNE _TX_OUT ; Нет? CLR R18 ; Да? Сбрасываем, переставляя на 0 _TX_OUT: STS IN_PTR_S,R18 ; Сохраняем указатель SEI ; Разрешаем прерывания RET |
Тут только один момент хитрый. Если у нас буфер переполнился, но не перехлестнулся, то его начало и конец совпадают, что как бы сигнализирует о том, что буфер пуст. Но на самом деле он полон непрочитанных данных и об этом сигнализирует флаг переполнения. Поэтому надо вначале проверять его, чтобы при не обходимости игнорировать признак равенства указателей.
На выходе функции Buff_Pop у нас в регистрах идут данные (R17) и код ошибки (R19). Если функция вернула 1, значит буфер пуст и регистр с данными можно игнорировать.
Запись в буфер задача более востребованная и чаще встречающаяся. И делается по аналогии с прерыванием RX
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | ; Load Loop Buffer ; IN R19 - DATA ; OUT R19 - ERROR CODE Buff_Push: CLI ; Запрет прерываний. LDI XL,low(OUT_buff) ; Берем адрес начала буффера LDI XH,high(OUT_buff) LDS R16,OUT_PTR_E ; Берем смещение точки записи LDS R18,OUT_PTR_S ; Берем смещение точки чтения ADD XL,R16 ; Сложением адреса со смещением CLR R17 ; получаем адрес точки записи ADC XH,R17 ST X,R19 ; сохраняем их в кольцо CLR R19 ; Очищаем R19, теперь там код ошибки ; Который вернет подпрограмма INC R16 ; Увеличиваем смещение CPI R16,MAXBUFF_OUT ; Если достигли конца BRNE _NoEnd CLR R16 ; переставляем на начало _NoEnd: CP R16,R18 ; Дошли до непрочитанных данных? BRNE _RX_OUT ; Если нет, то просто выходим _RX_FULL: LDI R19,1 ; Если да, то буффер переполнен. STS OUT_FULL,R19 ; Записываем флаг наполненности ; В R19 остается 1 - код ошибки переполнения _RX_OUT: STS OUT_PTR_E,R16 ; Сохраняем смещение. Выходим SEI ; Разрешение прерываний RET |
Пользоваться просто:
в R19 пихаем данные, вызваем функцию. НА выходе, в регистре R19 у нас код ошибки. Если там 1, то следующий байт писать нельзя — будет переполнение и перехлест указателей.
После загона данных в буфер надо запустить передачу. Я под это дело написал макрос
1 2 3 4 | .MACRO TX_RUN LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(1<<UDRIE) OUT UCSRB, R16 .ENDM |
Мы просто разрешаем прерывание UDRIE, а так как буфер пуст, то оно выполнится немедленно.
Из буфера данные забирает прерывание по опустошению UDR
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | UD_OK: PUSHF PUSH R17 PUSH R18 PUSH R19 PUSH XL PUSH XH LDI XL,low(OUT_buff) ; Берем адрес начала буффера LDI XH,high(OUT_buff) LDS R16,OUT_PTR_E ; Берем смещение точки записи LDS R18,OUT_PTR_S ; Берем смещение точки чтения LDS R19,OUT_FULL ; Берм флаг переполнения CPI R19,1 ; Если буффер переполнен, то указатель начала BREQ NeedSend ; Равер указателю конца. Это надо учесть. CP R18,R16 ; Указатель чтения достиг указателя записи? BRNE NeedSend ; Нет! Буффер не пуст. Надо слать дальше LDI R16,1<<RXEN|1<<TXEN|1<<RXCIE|1<<TXCIE|0<<UDRIE ; Запрет прерывания OUT UCSRB, R16 ; По пустому UDR RJMP TX_OUT ; Выходим NeedSend: CLR R17 ; Получаем ноль STS OUT_FULL,R17 ; Сбрасываем флаг переполнения ADD XL,R18 ; Сложением адреса со смещением ADC XH,R17 ; получаем адрес точки чтения LD R17,X ; Берем байт из буффера OUT UDR,R17 ; Отправляем его в USART INC R18 ; Увеличиваем смещение указателя чтения CPI R18,MAXBUFF_OUT ; Достигли конца кольца? BRNE TX_OUT ; Нет? CLR R18 ; Да? Сбрасываем, переставляя на 0 TX_OUT: STS OUT_PTR_S,R18 ; Сохраняем указатель POP XH POP XL POP R19 POP R18 POP R17 POPF ; Выходим, достав все из стека RETI |
В Случае переполненного буфера мы сбрасываем флаг переполнения, а когда данные все выгребем и указатели вновь сравняются, то мы запрещаем прерывание по UDRE. Тем самым, остановив передачу.
И кратенький пример на работу с буфером. Ничего не показывает и не доказывает. Просто гоняет данные не напрямую, а через буфера:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | ... RCALL Buff_Pop ; Берем данные из буфера CPI R19,1 ; Они там есть? BREQ LOOPS ; Нет? Ну еще раз INC R17 ; Данные увеличили на 1, просто так. MOV R19,R17 ; Переложили в R19 NewTry: RCALL Buff_Push ; Пихнули в буфер CPI R19,1 ; Буфер не переполнился? BRNE RUN TX_RUN ; Ecли да, то запускаем передачу RCALL Delay ; Ждем или передаем управление другой задаче RJMP NewTry ; А потом снова пробуем положить в буфер. RUN: TX_RUN ; Если все ок, запускаем передачу ... |
Примерно так.
Бег по граблям
А теперь разберем ряд основных проблем с которыми можно столкнуться при освоении USART, а также с методами их решения.
Пожалуй самый распространенный баг это циклическая инициализация. Т.е. когда инициализация USART засунута в главный цикл и каждую итерацию происходит его переинициализация. Разумеется он от такого затраха офигевает и отказывается работать. Поэтому сразу запомните раз и навсегда — все инициализации делаются только один раз.
Нет, разумеется можно потом что-нибудь подправить и заново переиницализировать, но не тогда когда идет передача. Сначала пусть устройство завершит свои дела, а потом уж его можно трогать за регистры.
Второй популярный косяк — аппаратные проблемы. Т.е. пыжишься ты с кодом, перебираешь биты настроек, а он не работает. И код уже проверен на десяток раз, а все никак. А проблема вполне может быть и с зависшим COM портом или FTDI. Либо подключил что-то неправильно. Самый простой способ проверить интерфейс это отключить от контроллера передающую линию (на Pinboard надо первести переключатель USART в положение OFF)
![]() |
Замкнуть RX на TX на выходе FTDI (или MAX232). Подключиться терминальной программой, например Terminal v1.9b. И отправить в порт байт. Он должен вернуться обратно. Если возвращается что-то не то, значит проблема в интерфейсе.
Третьими граблями (а может даже и первыми) являются проблемы со скростями и тактовыми частотами. Ведь передача то асинхронная, а значит если скорость не та на которую мы запрограммированы, то коннекта у нас не выйдет. Самая засада в том, что скорость контроллера так сразу и не определишь. Чуть ошибся в фуз битах и запустил, например, контроллер не на 8мгц, а на 1мгц. Либо выставил тактовый генератор, да завелся он не на частоте кварца, а на какой нибудь из гармоник (редко, но бывает). А еще в некоторых контроллерах есть фуз бит CKDIV8 который делит тактовую частоту на 8. В общем, если UART не работает или работает с ошибками, то узнайте ТОЧНО на какой реально скорости у вас работает контроллер. Сделать это можно, например, с помощью таймера. Настроив его так, чтобы он мигал раз в секунду. Если мигает так как положено — значит частота верная. А если нет, то искать почему — фузы, биты делителя, кварцы и тды.
По этой же причине, кстати, если в готовом устройстве написано, что надо кварц на 12мгц, то ставить надо на 12мгц! Не на 10, не на 16 или 7.32, а именно на 12. Т.к. скорей всего от этого кварца зависят тайминги протоколов.
Четвертые грабли — бездумное копирование инициализации из всяких обучалок. Внимательно смотрите что у вас включено и на что настроено! Какие прерывания включены/выключены. Если прерывание есть, а обработчика нет, то вы получите неслабый глюк! Особенно это касается прерывания по RXC, которой пока из UDR не считаешь не успокоится.
Ну и в пятых — следите за совпадением скорости передатчика и приемника. Т.е. если передача идет на 9600, 1старт, один стоп, без четности. То и принимать надо ее на тех же параметрах. И никак иначе.
Добавлю, что бит UDRE после сброса МК находится в установленном состоянии — это логично, т. к. регистр данных UART в начале работы пуст. Вообще, логика установки UDRE и TXC принципиально отличается. Это важно помнить при реализации буферизации вывода: прерывание надо обрабатывать не по UDRE, а по TXC. Иначе, при отсутствии выходных данных процессор будет впустую делать на каждый такт прерывание.
Не не не не :) По ТХС буфер нельзя пропихивать. Нам ведь его надо пропихивать фоном, по прерываниям, а не вручную. Байты уходят медленно, а ТХС генерится толкьо один раз — в конце посылки. Кто будет совать байты посылки из буфера в UDR? А нет таких героев.
Поэтому делаем так:
Вешаем прерывание по UDRЕ которое пропихивает все данные из буфера в UDR, а когда буфер опустошится само себя отключает.
А когда мы вручную пихаем что либо в буфер, то мы это прерывание включаем.
В результате полный автомат, отстутсвие тормозов главной программы из-за медленной передачи и никаких левых сработок. Ну бит сбросить/установить это можно в три команды сделать IN AND/OR OUT
Фак мой мозг! :-) А я так всегда и пропихиваю! Обработчик всегда удаляет из очереди байт и, если очередь не пуста, пропихивает в UDR следующий. Если пуста — все автоматически останавливается (прерывание отключать не нужно). В процедуре отправки, если буфер пуст, то первый байт отправляется в UDR. Т. е., конфигурацию UART я вообще не трогаю после инициализации (не считая полудуплексного RS-485 — там бывает полезно отключать приемник во время передачи).
В принципе, разницы особой нет — можно делать и так, и так :-)
Поготь, а как так происходит то? Т.е. у тебя отправляется один байт, потом стоп. Потом тупняк на основании которого генерится TXC который пихает в UDR еще один байт и так далее? Так? Т.е. байты у тебя идут с разрывами.
Да, ты прав — по UDRE получается правильнее! Я ошибочно думал, что UDR одновременно является сдвиговым регистром UART. Спасибо!
Пеленки ассемблерного кода =) Кстати не понял зачем ты запрещаешь прерывания? В твоем примере идет просто запихивание нужного байта в UDR. Да это будет работать, но только если в программе нету больше ничего что занимает процессорное время. А если там висит еще ШИМ на 100Мгц? Вот тут и начинаются проблемы. Поэтому лучше делать прерывания по приему и передаче символа. Так удобней и не будет потери данных.
Да тут я просто для примера. Чтобы не мешалось. Т.е. делаю пример гарантированно рабочий, что бы там не было накосячено выше и ниже по коду — но как дойдет до сюда, то сработает на 100%. А так конечно, еще с буфером в памяти. Главное на самом деле тут процедура инициализации UART =) Остальное все фигня.
Ладно, уболтал =) А насчет инициализации вставлю свою палку в колесо песне ;)
Вот мои инит:
// USART initialization
// Communication Parameters: 8 Data, 2 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 115200
UCSRA=0×00;
UCSRB=0xD8;
UCSRC=0x8E;
UBRRH=0×00;
UBRRL=0×03;
А вот твой:
uart_init: LDI R16, low(bauddivider)
OUT UBRRL,R16
LDI R16, high(bauddivider)
OUT UBRRH,R16
LDI R16,0
OUT UCSRA, R16
LDI R16, (1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<TXCIE)
; Прерывания запрещены, прием-передача разрешен.
OUT UCSRB, R16
LDI R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
; Формат кадра — 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор
OUT UCSRC, R16
RET
(да мой сделан на сях =) я это к тому что надо приводить примеры как у атмел =) )
К слову, в Си использование символических констант тоже никто не отменял. А некторые примеры у Atmel — чистейшей воды «индусский код» (например, AVR452 — код явно избыточен и только путает, т. к. контроллер CAN и так довольно загадочно документирован).
Код атмел тем и хорош, что если нужно быстрое «индусское» решение. Ты его получаешь сразу. Хочешь сделать лучше/быстрее/красивше (нужное подчеркнуть) берешь за основу код атмел и дорабатываешь.
Низнаю куда запихнуть вопрос, но вобщем он связан с UART!
Значит спаял я программатор и решил освоить UART, почитал, полистал вроде ничего сложного. Быстренько написал прогу на C в Code VisionAVR.
———-
#include
#include
void Send(flash unsigned char buf[])
{
int i = 0;
while (i != 6)
{
UDR = buf[i];
i++;
}
}
void main()
{
// BEGIN INITIALIZATION BLOCK
// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud rate: 9600
UCSRA=0×00;
UCSRB=0xD8;
UCSRC=0×06;
UBRRH=0×00;
UBRRL=0×81;
// END INITIALIZATION BLOCK
while (1)
{
Send(«Hello!»);
}
}
———————-
Перед этим спаял платку, куда впихнул кварц на 8 Mgz, и вывел RxD и TxD как я понял нужно отредактировать фьюзы что бы кварц заработал, попытался и больше проц не определялся)) ну ладно был второй!
Так вот спаял я по вашей схеме переходничёк на микросхеме ST232BN.
Все соеденяю вывод МК TxD к Rx а RxD к Tx, оба устройства запитываю от одного БП,
Запускаю Serial Port Monitor, и ничего ни одного байтика! Тыкаю щуп осциллографа к ноге у МК, видно что данные идут, тыкаю на ногу ST232BN, таже картина, прохожусь по контактам COM тишина. В чем может быть проблемма?
Скорость, четность, стопы совпадают? Выводы не перепутал? Попробуй поменять RX и TX местами.
Вот по поводу скорости она зависит от частоты, к плате припаян кварцевый ркзонатор, но я так понял, без вьюзов настройки фьюзов он не работает, на какой частоте работает тини2313 по умолчанию? вообщем и в программе и в прошивке стоит 9600, а стопы и четности совпадают.
Значит поменял, местами, появился сигнал на 2 разъеме ком порта, сейчас проснифим)
Эм.. щас даташит гляну. По дефолту Tiny2313 работает на частоте 8Мгц с предделителем на 8. т.е частота 1Мгц. Если сбросить фуз CKDIV8 то предделитель отключится и частота станет 8мгц. Если работаешь от кварца, то предделитель тоже надо учитывать. Я так его обычно сразу отрубаю нахрен, чтобы воду мне не мутил.
Предделитель можно отрубить и программно вот так:
OUTI CLKPR,1<<CLKPCE
OUTI CLKPR,0b10000000
OUTI CLKPR,0<<CLKPCE
Отлично, уже лучше только место данных идут 0.
Млин я думал над этим чтоб помень местами, но сам себе не верил что в схемах могут быть ошибки, спасибо!
Если лезет всякая муть, значит данные проходят, но скорей всего несовпадение скоростей.
Да не айс… проторчал, по перепрошивал и так и сяк, не отпраляет он ничего кроме 0 )) в статьях все просто инициализировал, и шли, хочешь байт, хочешь массив, шлю а принимаю нули. Может раскажете поподробней как слать и принимать байты на С.
Вот допустим выше указанный код неработает, если просто в бесконечный цикл поставить например UDR = 0×01, такая же картина, сегодня конечно ещё почитаю, но может кто здесь даст совет.
У тебя скорей всего проблема с тактованием. Разберись вначале на какой частоте у тебя работает Тини :) Спорю на 5 баксов, что про предделитель ты не знал и его не отрубил. А значит все твои расчеты UBBR пошли прахом. Порт принимаеть то принимает, но не понимает что там ему послали. Т.к. синхронизация по скорости идет.
Нашел заветную фразу, что фьюзы по стандарту настроенны на внутренний RC-генератор с частотой 1 МГц переправил программу все начал нормально передавать и принимать. Засунул все в цикл, только превые два байта, читаются)), впринципе думаю подправить чуток цикл, что б он, проверял прошол ли байт и только потом посылать второй, или задержку установить.
Кстати ещё где про фьюзы для моего МК нормально можно почитать, а то везде по разному такая билиберда, вот по одному мануалу установил, и усе, больше МК не определяется))
Как это где? В Даташите! :) Там все написано! У тебя какой программатор то? А то смотри, у разных прошивающих прог интерпритация фузов разная. Одни рисуют их инверсными, другие нет. А перепутешь — лочится кристалл :)
По дефолту не на 1мгц, а на 8мгц деленое на предделитель который по дефолту выставлен в 8! Так и получается 8/8 = 1МГц. Предделитель отключается либо сбросом фуза CKDIV8 либо программно, записью в регистр определенный — код я тебе выше уже дал. На ассемблере правда;) Но думаю ты найдешь в шите что там за бит я тебе указал и на сях его выставишь.
Все ясно, спасибо!!! Программатор я спаял c этого сайта котрый на Com порт, прошиваю прогой Uniprof.
Млин а у меня даташит не полный, там этого нет, где то на дисках должен быть полный будем искать ))
В унипрофе все фузы один в одни как в даташите. В сторонних мануалах может быть указано для понипрога или авр дудовской оболочке — там инверсны. Так что я обычно не гляжу что пишут в мануале, а выставляю исходя из смысла.
Все нормально принимает и отправляет, DI HALT у тебя в планах нет написание статьи о связи МК с внешней EEPROM, было бы интересно почитать, а пока погружусь в эту тему сам ;)
Это которые 24ххх на i2c протоколе? Напишу как нибудь :)
да, да именно они, буду ждать, ведь на Тини 2313 я понял можно это реализовать???
DI HALT извиняюсь за оффтоп но больше незнаю куда задать вопрос, а так как тема про EEPROM затронулась, прошу мне помочь!
Вообщем подключил я к своей тиньке AT24C256, все работает, записывал байт в ячейку по адресу 0xAA(тобишь в десятичной 170), так вот пытаюсь записать в меньше 170 не пишет, больше пробовал только 1000 тоже не пишет.
Так вот вопрос в память можно записать 32768 байт, какой у них диапазон адресов?
В даташите написано:
«Память размером 256 кбит внутренне разделена на 512 стр. по 64 байта в каждой. Для доступа к памяти по произвольному адресу требуется 15-разрядное слово адреса.»
Сегодня целый день проковырялся, и результат 0;
Надеюсь на вашу помощь!
Толком с АТ24 я толком не работал, так что вот так сходу не подскажу как там адресуется. Мне обычно всегда хватало внутренного епрома встроенного почти во все AVR. У меги8 пол килобайта епрома.
Насколько я знаю АТ24С256 не бьется на банки. У нее линейная память, а адрес задается двумя словами.
формат вроде бы такой:
ST:адрес девайса:RW:A:старший байт адреса:А:младший байт адреса:А:байт данных:А:SP это для одного байта. Для последовательности вместо стопа гонишь аскноледж и следующий байт.
«больше пробовал только 1000 тоже не пишет.»
Тэкс, как ты адрес задавал? Нука покажи мне кусок кода. 1000 в байт не влазит ;)
Вот допустим запись у меня
void write_byte_eeprom (unsigned int address, unsigned char data)
{
unsigned char sSREG;
sSREG=SREG
#asm(«cli»)
i2c_start(EEPROM_BUS_ADDRESS);
i2c_write((unsigned char)address>>8);
i2c_write((unsigned char)address);
i2cwrite(data)
i2c_stop()
SREG = sSREG;
delay_ms(11)
}
Вызываю функцию как в примере
write_byte_eeprom(0xaa,0×55) или тот же результат write_byte_eeprom(170,0×55)
Читаю от туда тоже нормально.
Я то думал что к аддресу ячейки просто нужно обратиться по её номеру)) но не тут то было!
полазив по нэту ничего вразумительного не нашел, даже банально как вообще организована память, вот допустим что такое старший и младший байт адреса, что такое 15-разрядное слово адреса, хочу тут копнуть чуть поглубже и разобраться в этом досканально, но незнаю даже с чего начать. Формулы бы как высчитывать следующий адрес, так я даже первого незнаю)) ладно утро вечера мудренее, буду завтра мозг себе ломать) может есть какие ссылки на эту тему, или статьи или книжки буду очень признателен ;)
Адресована она линейно должна быть. Т.е. адреса от 000000000000000 до 111111111111111 bin. Вот тебе и старший/младший разряды.
старший байт адреса шлется первым. За ним младший. Т.к. адрес 15 разрядный, то 7 бит старшего адреса роли не играет.
А запись тут страничная. Т.е. писать надо не более чем 64 байта за раз.
по 64 байта за раз это при страничном режиме записи, пока ещё это не освоил и хочу научиттся читать и писать в произвольную ячейку.
Значит первая ячейка это 15 нулей, а последняя 15 едениц, а как допустим получить доступ ко второй, третей, сто сорок первой ячейке, как высчитать их адресс?
адрес второй ячейки 000000000000001 bin =) Третьей 000000000000010 :)
либо я чего то не панимаю… либо… я вообще ничего не понимаю…))
Как я понял что бы обратиться допустим к ячейке №24576, мне нужно обратиться к адресу 110000000000000, те в Hex 0×6000.
Так вот задаю write_byte_eeprom(0×6000,0×55) и ничего не проиходит.
Что не так???
Все досканально просто, только вот низнаю почему до этого, это чудо не работало, просто вызывается
write_byte_eeprom(N,0×55)
где N, любое число от 0 до 32767, чего сним случилось, до этого то писал то не писал, спасибо, и извини что тут столько воды намутил ;)
Я не волшебник… я только учусь…
Бля, адрес передается двумя байтами. Вначале старший байт адреса потом младший. Я Не знаю чо там у тебя творит эта Сишная функция, поэтому пиши на ассемблере :)
КОроче, суешь вначале в i2c служебный байт. Потом шли туда число 0×60 (старший байт адреса) потом 0×00 (младший байт адреса) потом только байт 0×55. ФОрмат кадра я тебе уже писал.
Кстати какой тип данных у write_byte_eeprom(0×6000,0×55)? Я чето сильно сомневаюсь что первый аргумент это двубайтное число.
Я тут по ошибке грохнул твой коммент который с кодом. Он дважды застрял на модерации и я случайно два раза кликнул ;)
Там в первой строке:
i2c_start(EEPROM_BUS_ADDRESS); //Передача адреса памяти она задана как константа 0xa0(по даташиту)
Адрес у микросхемы памяти задается еще выводами А1 А2 и А0 так что проверь на каком реальном адресе пасется твоя ПЗУшка.
0xa0 это для записи а 0xa1 это для чтения, я там писал что функция уже сама делает все преобразования. Вот:
i2c_write((unsigned char)address>>8);
Это старший байт.
i2c_write((unsigned char)address);
Это младший байт.
i2cwrite(data);
а это запись символа. (см. код функции выше)
а не работало это все из за банльной ошибки.
Я не указал инициализацию I2C функцией
i2c_init() )))
Вот так все просто)
Сейчас, уже написал функцию котрая записывает и читает и всё это дело по UART передает, все отладил все работает ;)
А в чём может быть проблема. Написал обработчик прерывания
Interrupt [USART_RXC] void usart_rx_isr(void)
{
if (UDR == ‘C’)
{
eeprom_clear(); //Это моя функция
}
}
установи UCSRB=0×98;
У меня ещё есть обработчик, по изменению уровня на PB5.
Так вот, отправляю я к МК символ ‘С’, и все то ли подвисает, то ли что? незнаю, но больше МК ни на какие прерывания не реагирует.
Посмотри на ассемблерном коде, что там происходит и сразу будет видно где затык. В конце концов оттрассируй по этому прерыванию.
Я если честно в асме не силён, а что такое оттрасировать по прерыванию, да и можно ли в AVR Studio вызвать прерывание по USART, обычные получается, а в этот обработчик никак зайти не могу?
Ну так а кто виноват? Я же предупреждал, что микроконтроллеры изучать надо с ассемблера :)
В студии можно. Достаточно поставить флаг этого прерывани вручную и обработчик на него перейдет.
Кроме того, ничто не мешает вызывать тебе прерывание как обычную функцию RJMP inettrrupt_name из любой точки программы :) И опа!
Фигня там вообщем какя то происходит, обработчик прерывания работает, но как выходит из перывания, все регистры портов, регистры eeprom меняют свое значение, из за изменений на порту, вызывается другое прерывание, ну а дальше в цикл, и регистры портов постоянно меняются. А авр студио пишет
мол
Stack Underflow at 0×0106
Unintialized stack pointer used 0×0036
Гы. Косяк со стеком. Где то что то пошло не так :) Ты вручную в стек ничего не толкал?
Скорей всего переполнение. Проследи за регистром SP до вызова прерывания и что пихается в стек во время вызова прерывания и работы с программой епрома.
А как проследить за этим регистром, и что я должен там увидеть.
Во время вызова прерывания, записываются какие 3 байта (смотрю в окне (Memory->Data), задача функции eeprom просто прервнять двум переменным, котрые там записаны, 0. В принципе это и происходит, а вот при выходе из обработчика, начинаются лаги, перебрасывает в другой обработчик и там виснет, на стек весь заполняется какой то фигнёй и все байты становятся красными.
SP показывает на адрес в стеке (в конце ОЗУ) где находится в данный момент указатель. При вызове прерывания, по идее, в стеке должен ныкаться только адрес возврата (он там должен быть по любому) а еще возможно сныкиваются регистры которые модифицируются в обработчике прерывания (чтобы по возврату фоновая программа не свихнулась) Вот тока почему у тебя весь стек заполняется ??? ПО идее должно быть максимум на 32 (регистры)+2(адрес возврата) байт загрузка стека. И то далеко не всегда все регистры нычутся, компилятор должен быть умным и не сохранять тупо все. Посколькоу это прерывание, то параметры в него не передаются, а значит стек особо не нагружается. Но что там вытворяет компилятор я хз. Открывай листинг ассемблерный и смотри от вектора прерывания и до RETI из прерывания. Что у тебя пихается в стек и каким образом.
Когда я открываю окно дизасемблера, он вообще после выполнения обработчика, в цикл идет на 4 строках
LPM R0,Z+
ST X+,R0
SBIW R24, 0×01
BRNE PC-0×03
Вообщем было две ошибки, неправильно сконфигурировал USART, по этому и не работало, а фигня всякая в стек лезла из за того что прерывание вызывал #asm («rjmp _usart_rx_isr»), незнаю почему, но именно из за этого.
Бугагагага, жжошь!
Почемуто именно изза этого… не почему то, а именно иззза этого! Ты входишь в прерывание по переходу (естественно в стек ничего не грузится, т.к. по простому jmp) а при выходе из стека выгружаешь то, что туда не было положено — как итог у тебя указатель стека смещается и показывает невесть что, за выходящий адрес берется первый попавшийся в стеке мусор, программа выходит хрен знает куда и начинается кавардак.
Попробуй отключить нахрен оптимизацию. Изза нее часто много бед. Когда с виду рабочие программы перестают работать, т.к. компилятор повыкидывал из них наиболее значимые блоки в угоду оптимизации =)
Господа, позвольте вопросик!
А как соединить 3-5 контроллеров между собой, да еще если растояние между ними от 2 до 25 м? Можно ли вместо RS232 применить RS485? И как это лучше сделать, преобразовывать: UART->RS232->RS485-> линия <-RS485<-RS232<-UART, или можно прямо с контролера?
Есть микросхемы которые из стандартного UART делают RS485 точно не подскажу какая (MAX485???), но точно знаю что есть — видел в одном девайсе. А там либо по 4м проводам полнодуплекс, либо по двум односторонняя связь.
Но! 25м это не так уж много. Думаю хороший витой телефонный кабель и схема
UART-MAX232——-MAX232-UART будет работать на отлично.
А 2 метра так и обычный 5ти вольтовый уарт тащит на раз без помех.
как 25 метров? RS-485 (магистраль) он по своей природе разрабатывался для БОЛЬШИХ растояний. уменя связка: устройство адаптер RS232/RS485 витая пара 900метров адаптер RS485/RS232 комп, работает на скорости 57600
правда блоки питания (12V) для адаптера долго подбирал, чтобы падения напряжения было минимальное.
Ну так речь то не о RS485 на 25 метров, а RS232. А 485 пробивает на пару километров если на скорости 600бод или около того.
Здравствуйте. Есть задача также соединить два устройства и думаю что все-таки через сеть 485. Управляемое устройство (это коммутатор) имеет вход RS232. Подскажите новичку несколько контроллеров, которые имеют UART. Хотелось бы точное наименовани, чтоб не ошибиться потом при приобретении. Какие-нибудь простые.
ATTiny2313 (могу дать готовый кусок кода под 2313), ATMega8 это на вскидку. А по факту, по моему все AVR у которых более 8ног имеют UART на борту.
А зачем 485, если устройств всего 2? RS485 разрабатывался для того, чтобы простейшим способом, близким к RS232, обьединить НЕСКОЛЬКО устройств. Для этого их включают параллельнно, на одну линию с общим токозадающим резистором. Помехоустойчивость ее гораздо хуже, чем у 2х полярного сигнала на RS232.(При 2х полярном сигнале не происходит накопления заряда на емкости линии, аналогичном сглаживанию пульсаций выпрямителя). Для 2х устройств в 485 нет никакой небходимости, RS232 будет гораздо лучше. А UART сейчас есть практически в каждом PIC или ATMEL (кроме самых старых или примитивных, вроде PIC12C508). MAX232 — тоже везде полно.
Из простых PIC UART есть, например, в PIC16F628, (в 84 еще не было). Из Атмел — уже в AT90S2313.(в 1200 еще не было).
Да ну? С чего бы вдруг обычный двуполярный сигнал стал вдруг более помехозащищенным чем дифференциальная пара? У классического RS485 дальность составляет порядка километра на витой паре. У RS232 — всего метров 20.
DI HALT
Да, для большого расстояния мне нужно было. Я предполагаю, что 485 как раз более защищеннее будет. Здесь я имею ввиду метров 30. По стандарту, кстати, сеть до 1200м.
По поводу UART — я глянул на сайт атмеля и там в номенклатуре контроллеров только у одного в описании увидел «UART» :) Как раз в 2313. Да, скорей всего во многих он есть, но качать асе даташиты, чтоб узнать в каких есть, а в каких нет как-то не очен… :)
От готового куска кода не отказался бы — будет пример мне как работать с ним
а можно про ат команды в стиле вашй статьи из журнала хакер(немогу исходник найти по управлению сотиком)
Возникло несколько вопросов.
Есть RXC и TXC — флаги завершения приема и передачи. Есть прерывания. Причем последние можно запретить, а можно и разрешить.
Предположим мне нужно сделать отправку нескольких байт. Если у меня прога только этим и занимается, то я так понял в UDR можно писать и по TXC, и по флагу UDRE, так? Используя проверку командой SBIS. Т.е. отправка прошла — суем в UDR следующий байт. Или, UDRE свободен — опять же суем в UDR следующий байт. Не важно — с разравами или нет там будет процесс.
Но этот механизм нельзя же назвать «прерыванием» ? Прерывания это же «толчёк» процессору перейти на некоторый кусок кода, где что-то будет выполнятся. Т.е. не _мы_ что-то в цикле проверяем, а при возникновении прерывания во время выполнения основной программы происходит переход на этот маленький кусок кода. А остальное время в проце выполнялнялась бы основная программа. Так? Или как раз в основной программе и есть где-то строчка проверки? Ведь если мы вдруг попадаем в процедуру отсылки байтов с использованием UART, а он может долго отправлять, то пока все запланированное не отправим — не вернемся в основную программу. Так и застрянем в этой процедуре.
Я же себе представляю работу так — допустим пока идет отправка одного байта — крутимся в основной программе, что-то считаем, смотрим состояния пинов портов и т.д. Как только байт отправлен, переходим по прерыванию опять в процедуру отправки следующего байта и пока он там отправляется опять же продолжаем крутиться в основной программе.
Так ли это обычно реализовывают и возможно ли сделать именно так. А то прочитал статью про прерывания и не понял как все-таки их использовать.
Как обычно делается, если надо отправлять данные по медленному уарту фоном.
1)Делается буфер в памяти куда мы эти данные пишем. Ну или тем или иным способом даем понять, что у нас есть данные на отправку.
2) делаем обработчик прерывания на завершение отправки данных (TXCIE=1)
в обработчике делаем проверку нашего буфера на наличие данных под отправку. Если есть — отправляем первый байт в регистр уарта UDR и щелкаем счетчиком. Выходим. На все про все только время выполнения дестяка команд проверки. Остальное сделает аппаратный блок уарта.
Отправка:
Сознательно, в фоновой программе, закидываем в буффер данные (или просто подготавливаем данные к отправке, например указатель нужный заполняем) и !!!сами отправляем первый байт!!! по выдаче этого байта сработает обработчик прерывания из пункта 2 и отправит следующий байт, потом еще и еще, до тех пор пока не поймет, что слать больше нечего. На этом произодет выход из прерывания без отсылки байта и посылалка встанет до тех пор, пока мы снова не наполним буффер и не запустим вручную первый байт.
Да, если почитаешь первые два коммента, то там я писал, что корректней слать данные не по прерыванию ТХС, а по прерыванию на UDRE
Да, я это читал. То что можно перепрыгнуть в подпрограмму отправки данных по появлению флага — это понятно. Я так понимаю это надо делать в цикле основной программы — вставить проверку на наличие флага, так? Но в статье есть фраза «…биты RXC и TXC это флаги завершения приема и передачи, соответственно. RXC встанет когда непрочитанный байт вылезет в регистр UDR, а TXC встает когда последний стоп-бит прошел, а новое значение в UDR не поступило. Т.е. после прохода всех байтов. Также одновременно с этими флагами вызывается прерывание…» Получается, что есть два механизма, как я понимаю: отслеживание флагов и «прерывание». Если с первым вроде понятно, то как же использовать «прерывание»?. Или оно это и есть как раз проверка соответствующих флагов?
А вот как:
В прерывании, по UDRE делаешь отправку следующего байта в UDR. Так? Проверку на его пустоту делать уже не нужно — прерывание тому доказательство. Там же, в прерывании, делаешь проверку на то был ли этот байт последний. И если был — запрещаешь прерывание UDRE ее же обработчиком.
ТЕперь тебе надо отправить несколько байт. Ты в главной программе разрешаешь прерывание по UDRE. И шлешь первый байт. Все! Можно идти по своим делам дальше, прерывание само все сделает.
Дальше по опустошении буффера проц уходит на прерывание UDRE сам загружает в себе в UART следующий байт. И по его отправке снова сюда возвращается. Если все байты отправил, то запрещает вызов себя (чтобы на каждом такте не срываться по флагу пустого регистра, который будет стоять).
Автоматика!
Отправку можно сделать и по TXC это будет чуть проще в плане кода, но идеологически менее правильно. (об этом я и втолковывал Маддеву в самом начале комментов). Хотя я обычно делаю отправку следующего байта по Tx — лениво каждый раз UDRE запрещать. :)
Да да, это все я понял. Единственное, здесь и вообще везде где вырабатывается прерывание использование его — это циклическая проверка соответствующего флага? Одной командой? Если есть — перепрыгиваем на процедуру соответствующую, нет — выполняем дальше осн. программу до следующей проверки. Просто проверка всех прерываний ложится на плечи программиста. А ведь есть еще и команда запрета прерывания. Что она может запретить тогда? Перескок на процедуру в случае возникновения прерывания какого-нибудь?.
А ведь я про это писал!
Прерывание ведет себя похоже, но несколько иначе. При возникновении прерывания текущий адрес аппаратно суется в стек, а в программный счетчик запихивается адрес вектора прерываний. У каждого прерывания есть свой фиксированный адрес-вектор куда будет отправлен процессор при возникновении прерывания. Все эти вектора собраны в кучу в самом начале памяти программ и составляют таблицу векторов прерываний.
Вектора указывают на ячейки друг за другом. Так как у нас в одну ячейку можно сунуть только одну команду, а обработчик прерывания обычно занимает куда больше места, то выбора у нас особого нет — в эту ячейку мы пишем RJMP и упрыгиваем туда, где просторней и можно писать много, долго и счастливо. Если какое то прерывание нам не требуется, то от греха подальше лучше его заглушить командой RETI.
После обработки прерывания возврат к основной программе осуществляется командой RETI
Это то я понял. Это процессы уже в самом МК после того как программа написана, скомпилированна, зашита и работает. А в коде как надо писать?
«RXC встанет когда непрочитанный байт вылезет в регистр UDR, а TXC встает когда последний стоп-бит прошел, а новое значение в UDR не поступило. Т.е. после прохода всех байтов.
Также одновременно с этими флагами вызывается прерывание».
Мне надо в коде поставить проверку битов RXC (или TXC) и в зависимости от условий перепрыгнуть на процедуру? А там в конце нее не забыть еще прописать команду RETI.
«…Также одновременно с этими флагами вызывается прерывание» ну вот вызвалось оно. Дальше что. Само оно толкнет проц куда надо, или я контролирую этот момент?
Нет не надо тебе делать проверку этого бита. У меня он проверяется потому что ПРЕРЫВАНИЯ ВЫКЛЮЧЕНЫ ВООБЩЕ. Т.е. я вручную все делаю.
Тебе же надо:
1) Заполнить вектор прерывания по UDRE или RXC, записав туда RJMP куда нибудь.
Таблицу векторов прерываний смотри в даташите. Она у каждого АВР различается и расположена в первых 20-40 байтах от начала памяти программ.
2) Где нибудь написать обработчик прерывания.
И когда произойдет сработка прерывания проц сам прыгнет на адрес вектора, оттуда по твоему RJMP уйдет на обработчки, а вернется оттуда только по команде RETI которую ты сам же должен ему и прописать.
Типичная таблица прерываний из одного моего проекта:
;=========== Interrupt Vectors =====================================================================================
.ORG INT0addr ; External Interrupt Request 0
RETI
.ORG INT1addr ; External Interrupt Request 1
RETI
.ORG ICP1addr ; Timer/Counter1 Capture Event
RETI
.ORG OC1Aaddr ; Timer/Counter1 Compare Match A
RETI
.ORG OC1Baddr ; Timer/Counter1 Compare Match B
RETI
.ORG OC0Aaddr ; Timer/Counter0 Compare Match A
RETI
.ORG OC0Baddr ; Timer/Counter0 Compare Match B
RETI
.ORG OVF1addr ; Timer/Counter1 Overflow
RJMP t1int
.ORG OVF0addr ; Timer/Counter0 Overflow
RETI
.ORG URXCaddr ; USART, Rx Complete
RETI
.ORG UDREaddr ; USART Data Register Empty
RETI
.ORG UTXCaddr ; USART, Tx Complete
RETI
.ORG ACIaddr ; Analog Comparator
RETI
.ORG PCIaddr ; Pin Change Interrupt
RETI
.ORG USI_STARTaddr ; USI Start Condition
RETI
.ORG USI_OVFaddr ; USI Overflow
RETI
.ORG ERDYaddr ; EEPROM Ready
RETI
.ORG WDTaddr ; Watchdog Timer Overflow
RETI
.ORG 0×0013
Вот тут уже пошел код основной программы.
DI HALT, тебе вопрос, вроде детский ,но трепит мне нервы уже которую неделю. Мой AVR ATtmega8515 спит. Причина не ясна. Таковы симптомы: на кварце(4 МГц) имееться стабильная частота 4 МГц. Запитую свой AVR с 4х пальчиковых батареек т.е. около 6 В. Программу написаную на асемблере в АВР-студио от кампилированную через ПониПрог прошиваю в микруху. Все проходит удачно без ошибок. Но! при самой эллементарной программе, например, запись в порт С кода 0х41, реакции нет. AVR- спит! Тоже и с USART. ничего нет на пине TxD. Фьюзы устанавливал на свое усмотрение с книжкой в руке, т.е. лишнего ничего нет, только частота кварца на 4 МГц.
Думал микруха — брак, купил новую и все равно ничегою. Может у тебя идея есть поэтому поводу? Возможно где-то в фьюзах есть секрет.
Я даже начаю подумывать , что сама ATtmega8515 какие-то особенности имеет.
Запитую свой AVR с 4х пальчиковых батареек т.е. около 6 В.
Даташит надо было читать внимательней. Есть вероятность, что ты ее спалил нах — напряжение питания не выше 5 вольт.
Код программы в студию!
«Фьюзы устанавливал на свое усмотрение с книжкой в руке»
Ты в курсе, что в Пони прог фьюзы инверсные? Т.е. если в даташите написан 0, то в понипрог надо ставить галочку?
Я знаю что там фьюзы инверсны. Галочка- «0″ учел. я думаю если бы попалил микруху, на ножках кварца не было бы 4 МГц.
А вот это не факт. Генератор и порты это разные блоки. Ну и в коде могут быть косяки.
Код из микрухи читается обратно?
З.Ы.
Я понипрог на дух не переношу. На работе стояла у меня. Крайне странно работает эта софтина. Бррр…
Я после того как зашиваю прогу в микруху, сверяю коды записаные в микруху с кодами из АВР-студио. Может ли АВР-студио не верно кампилировать программу?
чем же тебе не нравиться ПониПрог? Простинко ,удобно Может что -то посоветуешь лучше.
Как высказался один камрад на форуме: «Пони прог — самый простой и эффективный способ заблокировать МК!»
Еще она была замечена в симуляции. Т.е. вроде прошивка прошла, но на самом деле нифига не было. На работе пару раз с таким сталкивался.
По кофейной гуще не гадаю. Покажи код.
Ну предположим вот эта программа пресылки одного байта в цикле по последовательному передатчику:
.include «m8515def.inc»
.list
.def temp=R18
.cseg
.org 0
lds temp,low(RAMEND)
out SPL,temp
M: clr temp
ldi R17,0×33
ldi R16,0
USART_Init: ;Установка скорости передачи
out UBRRL,R17 ;изменяя данные в R16,R17 вариируеться скорость передачи данных
out UBRRH,R16
;Включения приемника и передатчика
ldi R16,(1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<TXCIE);Разрешение приема и передачи, запрет прерываний
out UCSRB,R16
;Установка формата кадра: 8 бит данных, 1 стоповых бита
ldi R16,(1<<URSEL)|(0<<USBS)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC,R16
;Пасылка кадра данных длиной 5-8 бит
ldi R19,0×41 ;Тут хранится данное, которое нужно передать
USART_Transmit:
sbis UCSRA,UDRE ;Ожидание, пока буфер передачи очистися
rjmp USART_Transmit
;Помещаем данные (из R16) в буфер. Начинается передача
out UDR,R19
rjmp M
А вот ее код в хексе 20 91 5f 00 2d bf
22 27 13 e3 00 e0
19 b9 00 bd 08 e1
0a b9 06 e8 00 bd
31 e4 5d 9b fe cf
3c b9 f2 cf
Вроде ничего в глаза не бросается. Только зря ты в общий цикл включил иницализацию уарта. Она должна быть всего один раз. Может в этом косяк — при переинициализации может сбиваться передача, но не уверен — не проверял
В самой студии, в отладчике, как код себя ведет? Прогоняется по всем правилам? Если да, и в UDR данные пихаются, то они обязаны в той или иной форме вылезти через UART. Осциллографом бы поглядеть на линии уарта, что там происходит.
З.Ы.
Проводки RX и TX не перепутал? Стандартная и самая частая ошибка :)
З.З.Ы.
Сама схема на МАХ232 гарантированно работает? Вход на выход проверял?
В общем программа в симуляции работает как нужно. Согласен, это тупо включать инициализацию при каждом цикле, ну это просто не рационально. Исправлю.
А вот на осцилограмме все молчком :-(
МАХ232 проверял, коратил выходы Txd — Rxd и засылал данные. Они без искажения возвращались. То есть это штучка работает. Верно?
Вот что я еще заметил: на одной ноге кварца 4Мгц и 4Вольт, а на второй 4МГц и 1Вольт относительно корпуса. Это нормально?
Макс у тебя работает верно.
На кварце так и должно быть. Но можешь попробовать переключить на внутренний генератор.
А что у тебя с ресетом? Подтянул его к +5вольтам через резистор в 10к?
Нееееет. Ресет? я вообще от него отказался. Ведь там же внутренний сброс есть. Я оставил ногу ресет свободным.
Наивный. В результате у тебя МК от случайных наводок ресетится как попало и когда попало.
Сопротивление внутреннего подтягивающего резистора ресета порядка 100кОм. Это слишком много, можно считать вход RESET входом Hi-Z Сброс происходит при поднесении руки на расстояние до 5см.
Отказаться от ресета можно только на тини, где есть фуз бит ресетдизабл (при этом ресет нога превращается в ногу порта), но тогда отваливается последовательное программирование.
то есть, ты говоришь, мой МК спит именно по этому? Или есть еще какие-нибудь предположения? Если это именно по этой причине,мне прийдеться перетравливать всю плату:-( , а там уже налеплено…..
Эту подсказку я обязательно учту.
Напаяй ресет сверху на микруху. ПРоверишь предположение. Но должно быть оно. Кстати, ты программатор отключаешь от МК? Некоторые программаторы не дают стартовать МК, зажимая ресет в ноль
Программатор, я отключаю. Я считал так, что прошитый МК после того как всунул штерек питания начинает работать в соответствии с программой. После прошивки, я обязательно выдергивал программатор из платы с МК. Ну чтож попробую.
здравствуйте! на основе вашего (и многих других) написал такой код для атмеги 16-ой:
проблема в чём… пишет в порт всякую чушь! по спекам этого мк его дефолтовая частота RC=1MHz, по таблице на 1 МГц для 9600 (которые и необходимы) с ошибкой в +0.2% U2X=1 и UBRR=12 (делал и по вашим настройкам, но там -7%). COM сконфигурен вроде бы верно (на 9600), работу ST232 проверял замыканием Rx на Tx — идут правильные байты.
прошивается uniprof’ом верно, потом его закрываю — убирается reset и в порт начинает валиться чешуя.
не подскажете, в чём проблема может быть? заколебался уже тыкаться… :(
Во первых убери многократную инициализацию. У тебя цикл зачем то постоянно перенастраивает UART. Причем во время отправки байта :).
Код инициализации верный. Но ты уверен, что у тебя 1МГц? Проверь фузы на предмет этого. Проверь терминалку тоже :) Чтобы везде было 8бит, 1стоп и прочие мелочи. Рекомендую программу Terminal v1.9b
З.Ы.
тэг для кодооформлятора:
<pre lang=»AVR» line=»1″> код </pre>
блин, ё-моё, етиццкая сила!!! спасибо огромнейшее!!!
всё дело именно в реините!!!)))
фуууух!.. сколько дней ушло!..
а терминалка та самая ;)
Комментом выше чел тоже на реините погорел :)
ммм… снова затык) суть задачи — сделать некий параллелайзер… т.е., UART>параллельный и параллельный>UART. с UART’а в портА байты идут очень красиво, а вот если кинуть ногу INT0 на землю, то из Tx валится 0xFF. за исключением того, что прерывание надо делать по фронту, а не по низкому уровню (втупил я чего-то), что здесь не так?
Вроде нигде ничего бросающегося в глаза не вижу. Кроме того:
Зачем ты включил прерывание на отправку, если ты его не используешь? У тебя же отправка идет по флагу готовности.
Попробуй поставить после отправки в UART тупнячок, конструкцию вида
;Debug
CLI
Label: RJMP Label
На ней проц встанет и дальше не пойдет. А ты будешь точно знать правильно у тебя шлется из порта в UART или нет и поганит уже дальше. Ну и ресетом несколько раз проверь сработку.
Хинт: Отправку в уарт, имхо, лучше сделать по прерыванию на отправку, т.е. как только один байт отправился, прерывание на отправку инициализиуется снова и само в себя загружает еще один байт. Таким образом, у тебя и туда и обратно байты будут слаться непрерывно.
Обработчик будет вида:
Проверять готовность уже не придется — т.к. прерывание вызывается по готовности.
Можно сделать еще умней, фиксировать только изменения. Делаешь прерывание от таймера. И помнишь состояние порта в прошлой итерации. В обработчике прерывания сравниваешь с прошлым значением. Если оно изменилось — загружаешь в уарта. Если подобрать длительность опроса так, чтобы он был медленней уарта, то тоже проверка флага не потребуется.
АААААААААААААА!!! Ептыть!!!!
in R16, portB ;reading from portB
А это чо за хуйня??? Кто так из порта читает? Вот как надо!
in R16, pinB ;reading from portB!!!
аааа, работает всё!))
спасибо огромное, прям-таки спасли от разрыва затылка ;)
Ну дык. Надо тебя на пиво проставить при случае :)
жду в бабруйске (иркутске)! ;)
Всем привет! Уперся в проблему — Мега16, байты принимаю по прерыванию и отправляю, все ок. Не могу добиться стабильной работы счетчика байтов. Через Terminal v1.9b посылаю 12345678 (программа на каждый посланный байт должна возвращать его порядковый номер) После включения и первой посылке должна вернуть
01 02 03 04 05 06 07 08
после второй
09 0A 0B 0C 0D 0E 0F 10 и т.д.
Проблема в том, что работает это очень нестабильно — вот типичный ответ на отправку 2х посылок по 8 байт:
01 02 03 04 05 06 07 08
09 0A 0B 0C 01 02 83 01
или так
01 02 03 04 82 81 01 02
03 04 05 06 07 08 09 0A
Т.е. оно как бы пытается работать правильно, но что-то мешеет.
Привожу код:
Если есть у кого идеи — буду очень признателен
Смотри как такое дерьмо вычислять.
У тебя случайная плавающая бага — такое в 90% случаев изза срыва стэка, 5% вачдог, остальные — кривой алгоритм. Но тут алгоритм прост, поэтому думаем дальше.
У тебя счетчик Т0 задает счет байтов. Он же R16. Запоганиться в процедуре и прерывании он не может, он там не используется. Только для счета. А где он активно используется? В инициализаци!!! То есть у тебя почему то самопроизвольно сбрасывается МК. Если бы это было прерывание, то характер бы был более периодически. А тут случайная фигня какая то.
Поставь сброс вачдога в главный цикл и в начало каждого прерывания (команда WDR)
у тебя ресет подтянут резистором на 10кОм к +5? если нет — подтяни, без этого мк будет перегружаться как ему вздумается.
Далее, разные мелочи.
У тебя какая то запутанная и длинная инициализация уарта. Упрости, у меня например позырь как делается. Там реально в четыре команды все.
Не нужно выставлять направление в DDR на ноги UART. Это все будет сделано автоматически.
Не обязательно запрещать прерывание в обработчике прерывания. При вызове обработчика автоматически, аппратно идет cli а по выходу аппаратно же sei.
Сенкс, сделал, как ты говоришь —
1. припаял 10к на ресет прямо на микросхему (у меня на STK500 теститься)
2. инициализацию твою скопипастил
3. WDR вставил и в главный цикл и в обработчик прерывания
4. убрал команды запрета/разрешения прерываний в обработчике прерывания
Пока эффекта нет — вот что имею
81 01 02 03 04 05 06 07
08 09 0A 0B 0C 8D 01 02
03 04 05 06 07 08 09 0A
01 02 03 01 02 03 01 82
скинь мне мылом проект из студии, целиком в архиве. Завтра днем гляну и в протеусе прогоню.
Да, копипастить инит уарта это черевато. Надо не копипастить, а делать по аналогии. Дело в том, что в разных моделях мег он чуток отличается (бит урселект то есть то нет) и тупой копипаст работает далеко не всегда :)
C уартом согласен, но видно обошлось — работает.
Продолжаю разбираться — пробовал вместо автоинкрементного счетчика отдавать на выход фиксированное число, типа
ldi byte_count, $AA
MOV t0,byte_count
rcall SendByte
Та же фигня — иногда вместо AA возвращает 82 или еще что-нибудь.
Начал было грешить на шнур USB-COM, но вспомнил, что при передаче значения счетчика, он после сбоя как бы начинает считать заново, т.е. нарушается порядок счета — значит ошибка происходит до передачи — еще в контроллере. Но где именно?
Еще один эксперемент — Возвращаю то же, что и принимаю (эхо)
Если делаю через прерывание, как выше, то имею ту же проблему — регулярно байт искажается. Если делаю без прерываний в главном цикле, как показано ниже — то все ок, никаких сбоев.
MAIN:
WDR
rcall GetByte ;Принимаем символ в t2
rcall Echo ;Возвращаем символ на ПК
rjmp MAIN
GetByte: ;Прием символа
sbis UCSRA,RXC ;Ожидаем ASCII-символ от ПК (Пропустить следующую команду если бит в порту установлен)
rjmp GetByte ;Переход в начало цикла ожидания
in byte_res,UDR ;Сохраняем полученный символ (Чтение порта)
ret
SendByte: ;Передача символа на ПК
sbis UCSRA,UDRE ;Пропустить следующую команду если бит в порту установлен
rjmp SendByte ;Ожидаем освобождения буфера передачи
out UDR,t0 ;Передаем символ
ret
Echo: ;Передача сохраненного символа обратно на ПК
mov t0,byte_res ;Копируем символ в t0
rcall SendByte ;Передаем символ
ret
Похоже, что это какие то тонкости работы прерываний
Да, кстати вопрос уже идеологический — а как правильней работать с УАРТом — через прерывания или в цикле. Если верить книгам, то через прерывания нужно делать максимум и в то же время в тех же книгах примеры с УАРТом все, как один идут через цикл.
Вообще исходя из текущей задачи. Как эффективней так и делать. В реалтаймовой системе тупить на уарте нельзя, там на прерываниях все. Если же пофигу, то в цикле можно сделать. Я делаю под настроение, обычно в прерываниях.
Все, разобрался, мораль такая — если принимаешь в УАРТ по прерыванию, то и выдавать в него нуна по прерыванию (UDRE). Смешанные варианты вот так странно глючат.
Спасибо DI HALT! :)
Вообще странный глюк. Я с таким не сталкивался. Проект ты мне так и не выслал. Скинь, хочу поглядеть. Т.к. у меня работало и так и эдак. Без проблем
Да я отправлял вчера, вот закачал — http://www.thomas.ua/USART.zip так надежней
Ну как, смотрел? Может выложить то же, но без глюков, на прерываниях?
Обычно, если байты поштучно или в цикле поступают реже, чем время передачи байта, прерывания не нужны. Если же быстрее или сразу пачками, — тогда по прерываниям. Также и по приему: если цикл опрашивает приемник через интервалы меньше времени передачи байта — прерывания от UART не нужны.
Например, в моем роботе есть прерывание 1мс, от которого вертится куча программных таймеров. При 9600 бод байт передается за время чуть больше 1 мс, поэтому я в прерывание 1мс вставил также проверку готовности приемника и передатчика UART. (Наличие принятого байта или готовности буфера передатчика принять следующий). При одноранговой системе прерываний проще в одно прерывание заложить кучу проверок, чем разбираться с их источниками. В приоритетной многоранговой — дело другое… Хорошая была штука.
Уважаемый DI HALT,
вновь обращаюсь к Вам за помощью.
Теперь по поводу UART.
На плате, которая попала ко мне, стоит AT90CAN128 и MAX232A.
Кварц на 3,6864м.
Пытаюсь принимать и передавать данные по USART1. Но передача то идет, однако полная чушь. Какое бы значение я не передавал, всегда приходит хрень, за исключением $FF — это значение всегда приходит верно.
Кварц специально выбран по USART…
Проверял MAX232A — как у Вас указано, все ОК.
Помогите советом, что может быть?
Вот инициализация:
Заранее благодарен.
Такое ощущение, что у тебя рассинхронизация. Передай вначале штук 5 FF, а потом сразу же попробуй послать другое значение.
Ну и в терминалке скорость проверь, чтобы соответствовала.
Да, пробовал передавать FF потом другие — то же самое.
Интересная вещь: у меня MAX232 стоит рядом с МК на плате, так вот если я соединяю оба сигнальных вывода MAX, то через терминал все отправляется и принимается правильно (ноги МК при этом я отключал).
В то же время, если, восстановив все соединения после указанного выше эксперимента, и закоротив сигнальные провода на разъеме, который идет в РС, то МК передает и принимает все прекрасно. В смысле что передал, то и получил.
Как только соединяю МК и РС, так полная хрень. Может какая-нибудь кодировка? Кстати в терминалке я могу видеть эту жуть только в НЕХ формате. При переключении в любой другой ничего нет.
Проверь установки (длину Стоп-бита, наличие бита паритета, количество бит в передаваемом и принимаемом символе — может быть 5, 7, 8, скорость на обоих концах). Посмотри осциллографом длину битовой посылки на обоих концах. Может, неправильно посчитал коэффициенты деления. Проверь частоту кварцевого генератора контроллера — может, кварц возбудился на гармонике или вообще нихрена не стабилизирует.
Спасибо за совет.
Да, действительно, CKSEL фузы стояли совсем не так, как надо по даташиту при моем кварце. Переделал и все заработало правильно.
Спасибо всем.
При работе с COM портом была необходимость организовать счетчик принятых байтов. При приеме очередного байта устанавливался флаг разрешения прерывания счетчика T0
ldi t1,0b00000001
out TIMSK,t1
Предварительно в регистрах этого таймера устанавливался коэф. деления и начальное значение счетчика (соразмерно скорости обмена). Если до прихода нового байта срабатывает прерывание по переполнению таймера, то принятый байт идентифицируется, как относящийся к следующему кадру и счетчик байтов соответственно обнуляется.
Так вот обнаружилась такая хрень — установка этого флага автоматом вызывакт прерывание и как следствие потерю первого байта.
Это можно обойти если вместо флага разрешения прерывания в регистре TIMSK использовать регистр TCCR0
ldi t1, 0b00000101 ; Устанавливаем коэф. деления на входе таймера T0 — 1024
out TCCR0,t1
ldi t1, 0b00000000 ; Запрещаем счет
out TCCR0,t1
При этом все работает как надо. Но возникает вопрос — А нахера вообще этот бит в регистре TIMSK? И что еще он такого делает, о чем забыли написать в доках?
Ну во первых, прерывание ты просто разрешаешь, генерироваться оно сразу же не должно. Если сгенерилось, значит есть переполнение (в чем отлаживаешь? В Какой среде?)
Как можно обойти TIMSK через TCCR0??? это вообще из разной оперы. ТИМСК — это вкл/выкл прерываний а ТССР- прескалер таймера.
С какой радости
ldi t1, 0b00000101
out TCCR0,t1
Запрещает счет?
Запретить счет можно так.
ldi t1,0
out TCCR0,t1
Если ты хочешь отрезать пачки по таймауту. То тебе надо:
Заинициализировать счетчик
Разрешить прерывание таймера
Запустить таймер на нужном предделителе.
Ждать прерывание, которое тебе там что нибудь обнулит. Прерывание, если правильно задать начальное значение счетчика, сразу же не вскочит.
Посре прерывания нужно заново загрузить в счетчик начальное значение
сбросить прескалер
и ждать следующего прерывания.
to DI HALT
Да, конечно это я в письме ошибся, на самом деле запрещал так
ldi t1, 0b00000000
out TCCR0,t1
В счетчик таймера я загружал вполне вменяемые значения (например $01). Да я тоже считал что «прерывание ты просто разрешаешь, генерироваться оно сразу же не должно». Я просто стал запрещать прерывания при помощи другого управляющего регистра, если бы был какой нибудь баг с неправильной предустановкой счетчика или делителя и слишком ранним срабатыванием прерывания, то он бы проявился и в таком решении. Но в этом случае все работает нормально.
Это какого такого другого регистра? Глобального чтоль (I в SREG)?
В чем у тебя такая ботва получилась? В АВР студии?
Да нет — TCCR0 — остановка счетчика равносильна запрету прерывания.
По второму вопросу — да, в АВР студии
Ну это как в том анекдоте получается — нет ножек нет мультиков. Разумеется когда счетчик стоит прерывания не будет.
Скинь мне проект в студии, погляжу чо у тебя за фигня там с прерываниями творится. Любопытно.
to DI HALT
«Разумеется когда счетчик стоит прерывания не будет.» Ну да пришлось использовать такую фичу, т.к. прямым путем — откудать выпрыгивало это прерывание. Да, проект пришлю — почищу от хлама и пришлю.
Плиз помогите начинающему.
Канал таков: ATMega16-16PI — ST232BN — СОМ
Сперва неработало передавало белиберду. Почитал выши коменты, скачал даташип Отредактировал UBRR. Начало мои байты передавать, но только первые 2. После передачи второго баата URDE спадает и больше не восстанавливается, а у меня передача следующего идет после проверки URDE.
ПИШУ НОВИЧКАМ(как я).При передачи с МК AVR на комп к примеру буквы «G» — у меня тоже сперва неработало передавало белиберду .Ошибка моя была — не переключил на компе шрифт с «RU» на «EN».Сейчас самому смешно за убитые полдня, зато ДШ по UART наизусть выучил (хоть ночью разбуди-спроси -)).
А ты в какой проге пытался передать? В терминал1.9 ошибиться почти невозможно — там видишь что передается.
Прога обычная с Виндой XP которая идет, так в том-то и дело невнимательность: пошлеш букву и тут же пялиться на светодиоды(STK500). Смотриш что-то не то ,пошел код в AVRstudio смотреть,после ДШ изучать,потом на форумах аналогичные вопросы смотреть,а уж в последнюю очередь(как всегда,блин!)…..доперло….
Терминал 1.9 пробовал — понравилось.Нутром чую есть у проги куча скрытых для меня возможностей ,но при скудном знании английского в хелпе непрочитанных.
P.S(оффтоп): ДШ на русском для Attiny2313 это книга Белова «Миероконтроллеры AVR в радиолюбительской практике»(моя настольная книга,чего и любому новичку желаю).
Согласен ! :) хорошая книга! Пользуюсь ей уже год и читаю её вместе с Ревичем… Офигительная смесь знаний! … Так же рекомендую…
У меня стоит задача организовать обмен компа и МК с квитированием, то есть комп после отправки байта должен дождаться квитанции от МК. С МК разберусь, а вот можно ли использовать HyperTerminal для работы в этом режиме и как использовать — не могу понять.Или может кто подскажет другую доступную прогу для передачи файлов с квитированием?
Только свою написать. Впрочем, в Terminal v1.9b есть возможность написания скриптов на паскалеподобном языке. Может на нем что удасться.
Добрый день. ПОМОГИТЕ!
Мне необходимо прочитать 80 байт с софтового юарта и передать их в железный юарт.
Они читаются , но первые 2-3 байта всегда кривые. Остальные все нормальные.
Проверял осцилом, на входе в пик, все байты правильные.
В чем может быть ошибка??
вот код:
include
#fuses INTRC,NOBROWNOUT,NOWDT,NOMCLR
#use delay (clock=4000000)
#use rs232(baud=9600, rcv=PIN_B3,stream=SOFTUART,INVERT,TIMEOUT=5)
#use rs232(baud=9600, xmit=PIN_B2,rcv=PIN_B1,stream=HARDUART,TIMEOUT=5)
#INT_CCP1
void ccp(void)
{ for(i=0;i<80;i++)
{
f=fgetc(SOFTUART); // читаем с софтового юарта
//CAN[i]=f;
fputc(f,HARDUSART); // кладем в железный юарт
}
clear_interrupt(INT_CCP1);
}
main()
{
enable_interrupts(INT_RDA);
enable_interrupts(INT_CCP1);
setup_ccp1 (CCP_CAPTURE_RE);
}
ВОт собственно и все.
Очень буду благодарен за помощь!!!
Из этого кода непонятно ничего. Как работает этот софт уарт непонятно. ВОзможно первые два байта кривые изза того, что софтовый уарт не может ухватить синхронизацию четкую. Попробуй вначале передавать FF два раза.
Вобщем есть устройсто , которое уже нельзя перепрошить и т.д.
С RS232 этого устройства исходит ровно 80 байт каждую секунду.
Мне эти 80 байт надо отправить смской.
Для этого железный юарт пика смотри на модем.
А софтовый юарт пика использую для приема, тех самых 80 байт с внешнего устройства.
Использую для этого прерывания.
При попадании в прерывание, программа считывает 80 байт и заполняет ими массив.
А дальше передаю их модему (т.е. кладу в железный юарт). И все.
Проблема: искажает первые байты… не могу решить.
Сделай тогда наоборот — прием аппаратным УАРТОМ, а передача софтовым. Передвать куда проще чем принимать. Пусть принимает специально обученная железка, нежели куско чьего то кривого кода.
Очень правильная мысль!!! Но к сожалению применить нельзя. Так как устройства законченные. Т.е. доработать их нельзя.
Все что можно сделать — это перепрограммировать ПИК. :(
Теперь о наблюдениях:
Припаял кварц 12мгц на ножки пика, указал в директиве частоту 12мгц и использование внешнего генератора — ВСЕ РАБОТАЕТ!!!! И больше не искажает первые символы. НИКОГДА!!!
НО ВОТ НЕЗАДАЧА — НЕЛЬЗЯ допаивать дополнительные радиоэлементы (кварц с емкостями например).
Задача состоит в решении проблемы именно программным путем.
ПОКА НЕ МОГУ ДОБИТЬСЯ ТАКОГО РЕЗУЛЬТАТА!!! Кто хорошо владеет компилятором ccs и знает микроконтроллеры.. помогите пожалуйста
Правь исходный код. ПОдгоняй тайминги под уарт. Посчитай по ассемблерному листингу такты и время на 12мгц и на тех что есть и пересчитай.
А как это сделать? Я новичек в программировании.
В текущий момент, оптимизировал код по времени исполнения… уже искажает стабильно один символ (раньше стабильно 3 ,редко 2).
Более лучших результатов добиться не смог.
Ну смотри. У тебя есть программа которая на 12мгц работает нормально. А на тех что есть плохо. Это естественно, т.к. уарт асинхронный и все тайминги там ЖЕСТКО ЗАВЯЗАНЫ на тактовую частоту. Соответственно в коде у тебя (или у того кто делал библиотеку) просто неправильно расчитанные временные интервалы для считывания битов при приеме. Может ты где нибудь частоту неправильно в дефайнах указал и тайминги неправильно посчитались, может где то частота отдельно задается и там стоит 12мгц, а не та что есть. В общем, разберись как ведет себя софтовый уарт, откуда он берет тайминги. Для новичка задачка сложновата :) Тем более если дальше стандартных библиотек не лазал.
Незнал куда написать, но т.к. все началось с UARTа, то решил написать сюда.
UART ATmega16 через FT232RL соеденил с USB. Проверил (терминальными прогами). Все работает с обоими видами драйверов (VCP, D2xx). Но вот столкнулся с проблемой написания программы со стороны компа. FTDI с D2xx дали библиотеку работы с их микросхемой, да все работает (принимает, отправляет), но куда засунуть эти процедуры, т.е. например как у UARTа закинул упровление на прерывание, а у USB чет я такого немогу найти. Подскажите как организовать теневой опрос моего USB устройства?
P.S. сформулировал проблему как смог(
А виртуальный ком порт чем плох? Ведь FTDI организует именно его.
Скорость маленькую дает — 1 Мбит, а если D2xx — то они 3 Мбита обещают.
Вообще — то стандарт RS232 предусматривает скорости максимум 56000 бод. Все остальное — это уже не RS232, хоть некоторые производители в последние годы и делали COM — порты на 115000 и даже 256000 бод. Для больших скоростей есть другие протоколы. Для мегабит и кабель другой нужен, и порты, и прочее, и прочее. Нужны мегабиты — используй USB, ITHERNET, TCP/IP, SFX/SPX и прочее… Не нужно ездить по дороге на реактивном самолете, даже если он у тебя есть. Дорога не для того создавалась.
написал программку что контроллер шлет постоянно 0х42, типа звездочку ‘*’. чаще всего доходит правильно, но иногда начинает идти бред в перемешку со звездами, а потом и вовсе останавливается, видимо идет уже такой бред что terminal не понимает совсем. Это почему может быть? наводки?
Блин. Учусь читать. Подтянул reset и все вылечилось.
подскажите можно ли в процессе выполнения программы на микроконтроллере поменять скорость работы USARTa. просто изменение значений UBRRH:UBRRL непомогает, хотя может я некоренктно их меняю, вот код:
#asm(«cli»)
UBRRL=0xA0;
UBRRH=0×01;
UCSRB=0b00111000;
#asm(«sei»)
после сброса микроконтроллера USART работает на скорости 9600. меняю скорость на 4800 и разрешаю прерывания для DRE
Должно работать. Я часто так делаю
Что-то и у меня бред какой-то получается. Правда я на Си пробывал. Если выводить какую-нибудь строку из флеш в цикле, то она идет пока есть питание. Если же значение с АЦП преобразованную в строку, а потом ее через функцию puts() и также в цикле пускать п порт, то сначала идет нормально, а потом вывод останавливается и в УАРТ шлется только символ 0A, наверное здесь проц подвисает. Другой вариант моей проги сначала то что надо, потом почему-то нули, потом опять то что нано и опять нули и т.д. Вывод в УАРТ идет не через прерывание, а через конторль освобождения регистра UDR. По скоростям все согласовано.
Чо я могу посоветовать. Вскрывай ассемблерный листинг и зырь что у тебя там происходит. Сразу поймешь что там нагородило.
Да, попробуй еще оптимизацию отрубить.
Здравствуйте DI HALT.
Помогите пожалуйста.
Схемка на ATMega8535, он отправляет команду телефону, а телефон молчит.
Подключал к компу (схемку) работает, телефон с компом тоже общается (правда только на 19 200). Думаю что дело в скорости.
Почитал на форумах, говорят что кварц надо ставить на 7,3728 Мг. Может можно без него?
Если да, то как?
Если нет, то скажите пожалуйста, что нужно в коде изменить, что бы контроллер от кварца работал?
\\\\\\\\\\\\\\\\\\\\\\\\\
uart_init:;
.equ XTAL = 8000000; частота процессора.
.equ baudrate = 19200
.equ bauddivider = XTAL/(16*baudrate)-1
outi UBRRL , low(bauddivider)
outi UBRRH , high(bauddivider)
outi UCSRA , 0
outi UCSRC , 1<<URSEL|3<<UCSZ0
outi UCSRB , 1<<RXEN|1<<TXEN|1<<RXCIE|1<<TXCIE
\\\\\\\\\\\\\\\\\
А к компу, к КОМ порту подключать не пробовал? А то может у тебя шлется все нормально, а просто ты с командами накосячил.
Во вторых с какой точно частотой у тебя работает Мега? Точно с 8мгц? Уточни в даташите на мегу на какой частоте она работает по дефолту (вроде бы там 1мгц, но я не уверен)
В третьих, программно ты МК на кварц не переключишь, надо через программатор менять Fuse биты. Если не знаешь что такое, то лучше не лезь — ошибешься и МК В помойку. Почитай сначала даташиты и мануалы. У меня все в Учебном курсе АВР есть.
Кварц на 7.37 ставят когда хотят получить очень точный UART на высоких скоростях, с минимумом ошибок. Тогда да, обычно на внутреннем все работает. Я сколько с АВР работал — ни разу еще не приходилось юзать внешний кварц.
Телефон подключал к компу, все работает (только на 19 200).
Если в МК ставлю 8 Мг, и скорость 19200 то в комп приходит на скорости 2400,
а если ставлю 4Мг то прихадит на скорости 4800. Так и должно быть?
Пробовал ставить 1Мг и 9600. В комп приходит как раз на 9600, но когда поменял на 19200 (при 1Мг) то приходят ироглифы всякие разные(. На любой скорости приема.
Как мне быть?
Частоту по дефолту обязательно посмотрую.
ЗЫ. Огромное спасибо за ответ!
Так это:
.equ XTAL = !!!!!!!!!8000000!!!!!!!; частота процессора.
и вот это:
.equ baudrate = !!!!19200!!!
Для кого написано?
Да, там еще бит есть U2X он удваивает скорость обмена. Я обычно его не юзаю. Если ты взял мою инициализацию, то его там тоже нет (и не надо)
По дефолту (если фузы не менять) скорость Мега8535 — 1Мгц.
Так что:
.equ XTAL = 1000000
.equ baudrate = 19200
и все заработает
Хотя нет, тебе надо Fuse bits переставить на 8мгц. Т.к. на 1мгц на частоте 19200 погрешность работы уарта 8% это сильно дохрена — поэтому кракозябры.
А где в вашем курсе про Fuse bits можно почитать?
http://easyelectronics.ru/avr-uchebnyj-kurs-konfiguraciya-fuse-bit.html
огромное спасибо за помощь! Буду разбираться!
Здравствуйте DI HALT. Это опять я:)
Вот смотрите, кусочек кода:
.org 0×0000
rjmp Reset ; на метку Ресет
;сдесь должна быть табличка прерываний
Reset: outi SPL,low(RAMEND) ; инициализация стека.
outi SPH,high(RAMEND)
rcall uart_init ; вызов подпрограммы инициализации UART
;———-настройка портов
CLI ; запрещаем прерывания,
Main: WDR ; Пинаем собаку.
;————сдесь ожидаю, а если что не так, то на Alarm0
RJMP ALARM0
rjmp main
ALARM0:
;——-сдесь идет передача по uart
STOP0: WDR
SBIC PINA,0
RJMP STOP0 ;сдесь зацикливаемся,
ret
Так вот, при выполнении команды ret программа возвращается на метку reset, а там происходит инициалицация стека, мне интересно, а если у меня там данные какие были (в стеке), они удалятся?
А вот если вместо ret поставить команду RJMP main, то после ее выполнения повторно отправляются данные по UART, почему?
И еще скажите пожалуйста, где меньше погрешность при передаче по UART
если я сделаю тактовый генератор (RC) приблизительно на 7,3Мг
или если выставлю тактовую частоту контроллера 8Мг?
С уважением, Михаил.
Бегом учить матчасть! В процедуры уходить надо по RCALL и выходить по RET. А не по RJMP который просто переход. Соответственно у тебя срывает стек и проц перезагружается.
А по поводу того, что у тебя после перехода обратно на Main идет повтор отправки по UART так ты где то с условием в «;————сдесь ожидаю, а если что не так, то на Alarm0″ что то накосячил, что оно у тебя пускает дальше.
di_halt приветствую, вобщем трабл с кодесом контроллер АТмега16 с кварцем на 12 МГц и CKSEL3..0 = 1111 вобщем вроде бы на 12 МГц работает… проблема вот в чём — отправляю в контроллер 1 байт.. приходит 3 байта мусора, вот код:
.equ fosc = 12000000
.equ baudrate = 9600
.equ ubrr= fosc/16/baudrate-1
init_uart:
ldi R16, low(ubrr)
out UBRRL,R16
ldi R16, high(ubrr)
out UBRRH,R16
ldi R16,0
out UCSRA, R16
ldi R16, (1<<RXCIE)|(1<<RXEN)|(1<<TXEN)
out UCSRB, R16
ldi R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
out UCSRC, R16
ret
… получаю данные так
RXcomplete:
in R16, UDR
cli
call out_data ; тут вывожу полученный байт через свою либу на ЖКИ — вобщем получаю 3 байта вместо одного
sei
reti
ну на компе в проге разумеется выставляю 9600 / 8 / 1 в чём проблема никак не пойму =(
out_data взываная вручную работает правильно? Шлет то что надо? Если нет, то разбирайся с бодрейтом и настройками уарта.
По поводу прерывания RXcomplete
Тут грубейшая ошибка
1) ты входишь в прерывание и меняешь R16, мало того, ты вызываешь out_data которая тоже наверняка использует какие то регистры.
Соотвественно, перед тем как что то менять в прерывании нужно все регистры которые меняют свое значение сохранить в стеке, а перед RETI достать их оттуда. Так что PUSH и POP тебе в помощь. Также не забуlь про SREG его тоже надо сохранить. Это связано с тем, что ты не знаешь где будет вызвано прерывание и не можешь предугадать ход какой части кода затронет изменение регистров.
Ну и второе, при входе в прерывание не обязательно запрещать их командой cli — это происходит автоматически, аппаратно.
благодарю за дельные советы, кстати out_data норм работает — она пока только приветствие выводит… проблема видимо действительно в настройках уарта — закоротил TX-RX и всё что отправляем — возвращается, в прерываниях не сохранял реги — да действительно прога может в любой момент прерваться для сношений с компом и логика основной проги будет нарушена — как-то не подумал, кстати насчёт частоты кварца для обмена по RS232 — я где то слышал там «специальные» кварцы какие то — так вот это актуально или на чистых 12.0 МГц тоже будет нормалёк?
Спец кварцы нужны для очень высоких частот и когда шлешь на большие расстояния. В общем, там где критично. Обычно же на чем угодно, главное УББР правильно рассчитать.
Привет DI HALT
Есть такая задачка: необходимо принять два 4х значных двоичных числа, дополненных кодами возврата каретки и перевода строки, через уарт, микропроцессор их сложит и вернет результат туда же через уарт. МК ATmega16 с кварцем 14.318 МГц
Вот что я навоял, раскритикуй =)
Топорно, в лоб. Но вроде должно работать. Работает?
В Proteus`е работает, в корпусе не проверял ещё.
почему вы в обработчике прерывания не хотите выполнять главный цикл, а делаете только прием одного байта?
а в главном цикле например усыпить проц, что-бы не грелся.
Ну во первых усыплять проц смысла тут нету. Он и так мало ест. А во вторых в обработчике надо делать быстро и сваливать оттуда. Обработчик должен быть коротким.
@Обработчик должен быть коротким.@
это я усвоил, просто интересно если например 4 байт прейдет и запишется в R16
например когда выполняется строка
80: cpi r16,13 ;а вдруг возврат каретки? =)
может там и был возврат каретки но теперь там 1
и программа в ауте?
Для этого обработка символов в программе должна быть быстрей чем они поступают из интерфейса. Если это невозможно, то юзать приемный буффер и в прерывании нажирать его, а потом медленно жевать в главном цикле
Вот возник такой вопрос, подскажите,пожалуйста, кто знает.
Допустим при передаче по UART’у возникла ошибка четности/фрейма при этом возводятся флаги PE/FE. Они сбрасываются после чтения из UDR или их нужно вручную сбрасывать?
UPD: Отмена. Нашел в даташите.
И у меня вопрос подскажите пожалуйста существуют ли какие нибудь стандартные байты начала и конца посылки для uart?
Например в протоколе rs485 признак начала 3A («двоеточие»), а признак конца 0D и 0A («СR» возврат каретки), а как правильно делать для uart?
А зависит от принимающего софта. UART это всего лишь физический протокол.
Ну и ладно поставлю FFFF :)
Привет)
Мне хотелось бы реализовать Режим многопроцессорного обмена.Поскольку у меня много устройств работают на одной частоте, связаны между собой и их нельзя загружать парсингом того что пришло в уарт.Мне бы простой пример генерации байта адреса))
в датащите всё это описанно вскользь.Думаю так : 1.пришёл байт адреса (байты данных идут лесом) проверяем со своим адресом. 2. если совпало ловим данные пришёл $FF ставим MPCM в еденицу и снова фильтруем данные тоесть прыг на 1.Контроллер ATTiny2313 но пример можно и на меге разберусь)
Туплю в написании кода .Заранее СПС!
> DI HALT июня 14, 2009 at 19:51
> Для многопроцессорного режима куда лучше использовать I2C.
> ТАм и адресация и разрешение коллизий.
> У USART можно только на базе архитектуры Token Ring что то сделать.
> Что медленно и неуклюже. В промышленности ЕМНИП на этом принципе работает RS485
Ну если Мастер на линии один, то UART (в режиме 9-ти битовых посылок) наверное лучше всё-таки. И код попроще, и скорость побольше. И тем более, если планируется только передачи Мастер -> Слейв. Тут ещё и одним проводом меньше.
Ну тогда гнать по вначале байт адреса, потом байты данных. Слейвы сидят и снифферят. Кто свой адрес узнал — обрабатывает. Остальные байты просто сливают в dev/null (надо чтобы не прозевать стоп). Как получено определенное количество байт — слушаем дальше. Данные само собой надо слать пакетами, чтобы все слейвы знали длинну пакета.
> Остальные байты просто сливают в dev/null
Дык остальные байты просто игнорируются аппаратно. В смысле прерывание не генерируется. Это ж специальный режим такой, когда 9-й бит является признаком адрес/данные. Multi-processor Communication Mode. Включается битиком MPCM в регистре UCSRA.
> Данные само собой надо слать пакетами, чтобы все слейвы знали длинну пакета.
И даже это не обязательно в простейшем случае.
1. Ждём байт адреса.
2. Если адрес наш, то все следующие байты наши до того момента, пока не будет получен адресный байт (9-й бит = 1).
3. Если адрес не наш, то Goto 1.
ps: Да кстати я не знаю почему назвал байт адресным, правильнее наверное назвать его служебным и кроме адреса содержать он может ещё много чего, например команду, общую для всех или признак конца передачи, …это уже от фантазии зависит.
Может кто кинуть код многопроцессорного режима… нужен мастер …
Здравствуйте уважаемый Di_Halt. У меня в контроллер по Uart (мега 8535) приходить строка символов, мне ее надо сравнить с константой. Никак не могу придумать, как это можно реализовать, подскажите пожалуйста!
Ну или хотябы на мысль наведите:)
А кстати, хороший вопрос. DI HALT, может в курсе опишешь какую-нить элегантную
процедцрку (на асме естественно) по декодированию команд принятых УАРТом.
На входе — принятая строка символов и таблица с командами во флеши, на выходе — код команды.
Может там какие хитрые приёмы есть, а то чё-то как мозги не напрягал, всё как-то громоздко/топорно получается. (Даже на Си стал посматривать…)
Ладно, на досуге напишу процедуру проверки строк через XOR. Думаю это оптимально будет. ЗАмысел понятен или пояснить? ;)
Да понятно, вроде… Хотя нет, не понятно — а чем XOR лучше обычного CP в данном случае?.. Ладно, подожду примера.. или сам подумаю :-)
Да можно и CP, мне XOR привычней :)
На каком языке то?
на Assemblere
Думаю проще чем XOR тут ничего не придумать. Зажираешь строку в буффер. Дальше берешь и начинаешь этот буффер циклично XORить на ту строку с которой сравниваешь. Прям побайтно. Если в результате всей операции у тебя получился 0 значит строка та самаяи в бит в бит совпадает со сравниваемой.
Спасибо за совет! Надо попробывать.
Да я понимаю что получится неуклюже но я начинающий поэтому I2C для меня тёмный лес.
Куча устройств в доме работает по радиоканалу.Я это чтобы небыло мешанины в эфире.Никак не пойму как собрать до кучи байт с адресом там ведь первый стоп бит должен быть 1 а у данныйх как обычно 0.Вот тут я и туплю у меня постояно данный прут(( если не сложно покажите на асме как это сделать . Ещё раз спасибо
Мешанина у тебя будет в любом случае. Тут либо применять модули с адресацией RC1240 например, либо делать адресацию самому. В любом случае должен быть тогда хотя бы опрос, т.е. мастер выдает адрес и сразу же команду, потом слушает. ВСе остальные слушают и если поймали свой адрес, то отвечают.
Вот я и хочу замутить адресацию сам.. У нас в лабазах ничего приличного не продаётся(( Единвенное что нашёл на рынке какието китайские модули на 433MHz
но работают они норм правда тупые ничего не умеют.Таких модулей я накупил много а теперь пытаюсь всё упорядочить. Вот и хочу применить такой режим а ума не хватает (( А «мешанина» это всмысле чтобы разные устройства друг дружку не пинали.
DI_HALT, а вы не знаете сколько у меге 8535 логическая единица. Я вот телефон подключаю, на него данные нормально уходят а ответ (от телефона) не приходит.
RX меги и TX телефона цепляю на прямую.
Причем если с компа посылаю (через дата кабель от этого же телефона Simens C45) то все приходит
На память не помню, в даташите погляди, что то около 2.5 вольт и выше (для 5 вольтового питания). По крайней мере 3.3 вольта с сименса 65го вполне нормально доходили.
А ты мегу каким напряжением питаешь? Когда у меня было 5ти вольтовое питание, то я
TX меги заводил на RX телефона через стабилитрон.
А обратно просто напрямую
так и я так же ципляю.
Мегу питаю от компового блока питания, 5В.
Так через кабель мега все отлично принимает!
Все, проблема решилась, только не понятно как)
Возникла другая проблема.
Если я сначало посылаю байты, например:
putc ‘A’
putc ‘D’
putc ‘C’
putc ‘D’
putc ‘E’
а потом сразу же начинаю принимать:
in_com: ;прием байта в r16
WDR
sbis UCSRA,RXC
rjmp in_com
in R16,UDR
то контроллер принимает только что отправленные байты, а вот если подождать пару секунд и начать принимать, то тогда все хорошо.
Почему так, в чем я ошибся?
Заранее благодарен за ответ.
putc-марос, который кладет байт в r16 и вызывает процедуру:
uart_snt: sbis UCSRA,UDRE
rjmp uart_snt
out UDR,R16
ret
Прием байта надо делать по прерываниям. Т.е. активизируешь UART, разрешаешь прерывания. Потом от вектора прерывания по RxC делаешь RJMP на обработчик прерывания.
В самом обработчике
1) Сохраняешь регистры которые используешь в стек
2) Сохраняешь в стек SREG
3) Делаешь нужный экшн
4) Достаешь из стека сохраненное
5) RETI
Примеров работы с прерываниями у меня было описано, в том числе и на RxC
Мужики!!Помогите!!Работаю с STK-500 и STK-501 , на ATmega128.Настроил UART на приём , всё чётко принимает с Hiper Terminal.А на передачу не могу , передаёт ,но какую-то хрень,понимаю что похоже проблема в синхронизации по скорости , стоит кварц 16 мГц , UBRR=51 это 19200 и нифига((( что терминал хрень получает что если на второй ATmega128 посылаю.Зато в ISIS Proteus всё работает.Помогите очень нужно.
Добавлю и я свои 5 копеек ;-)
Хотелось подключить Atmega16 к компу по UART, max232 под руками не было, нашел в инете схему согласования на транзисторах.
сайт http://www.qsl.net/pa3ckr/bascom%20and%20avr/rs232/index.html
схема http://www.qsl.net/pa3ckr/bascom%20and%20avr/rs232/rs2324.gif
собрал, закоротил, эхо-ответ идет, ну думаю «щас как все заработает».
подключил к МК, нашел самую простую прогу в инете, скомпили ….. нифига
по терминалу плзут ёжики
стал читать про настройки, таблицы в даташите смотреть — ага, не те константы в настройках
частота кварца у меня 14МГц, таблица 70, на стнарице 170, тааак, UBRR=95
ёжики
блин, короче что я только не читал уже, часов с 15 до 21 мучался — нифига
все, задолбался
пора завазывать
у тут на последок мысль
(я компилируюсь в CodeVisionAVR V2.03.4, там есть визард который сам делает начаьный код)
запустил визард, частота процессора, как всегда, 14МГц, используем UART и туда и сюда, прерывания запретить, поехалиииииииии
опа ??????? UBRR=5a
запускаем, оооооооооооооооооооооооооооо !!!!
почти, почти, чуть чуть срывает сигнал, ану UBRR=59
запускаем, совсем сорвало
UBRR=5B
УРААААА, заработало (с) Кот Матроскин
все стабильникько так…. Чудесно.
ану посчитаем частоту?
UBRR=FOSC/16/BAUD-1
5B = ??? / 16 / 9600 — 1
??? = 14131200 Гц
а визардами пользуються только «или аристократы или ….» — сами знаете, и тем не мение
оказалось что кварц у меня не такой как в даташите, а я забыл
Комментарий добавился не туда, сори.
Это были просто размышления на тему UARTA, а не продолжение обсуждения -
RMiSe 15 июня 2009 20:12
Мужики!!Помогите!!Работаю с STK-500 и STK-501 , на ATmega128.Настроил UART на приём , всё чётко принимает с Hiper Terminal.А на передачу не могу , передаёт ,но какую-то хрень,понимаю что похоже проблема в синхронизации по скорости , стоит кварц 16 мГц , UBRR=51 это 19200 и нифига((( что терминал хрень получает что если на второй ATmega128 посылаю.Зато в ISIS Proteus всё работает.Помогите очень нужно!!
А он точно то принимает? Т.к. если принимает то и передавать должен. Настройки то там едины.
Кварц начинает влиять на качество только на скорости свыше 100кбит, там да, нужен специально заточеный кварц. На 19200 можно на чем угодно, хоть на RC — проблем быть не должно, не та скорость.
Может у тебя уарт захлебывается или инициализация уарта в общем цикле крутится и он у тебя офигевает от постоянных перезагрузок контрольных регистров.
Принимаю точно.Пишу число или букву в терминале отправляю и смотрю на лампочках STK этот символ в ascii коде всё совпадает.
А вот мой код программы , без всяких циклов , просто передаю число и конец.
Я разные скорости пробовал , уже голову сломал , не пойму в чём дело((
.include «m128def.inc»
INIT:
ldi r16,0×31
ldi r17,(1<<TXEN0)
out UCSR0B,r17
ldi r17,51
out UBRR0L,r17
ldi r17,(1<<UCSZ00)|(1<<UCSZ01)
clr r26
ldi r27,0×95
st X,r17
WAIT_START_TRANSMIT:
sbis UCSR0A,UDRE0
rjmp WAIT_START_TRANSMIT
TRANSMIT:
out UDR0,r16
END: rjmp END
Помагите пожалуйста разобраться, где то есть ошибка!!!
Mega 2561. Пересылаю 2 байта (передатчик отправляет, приемник получает все ок!) но второй раз, по истечению времени, передача не идет причем пошагово (AVR Studio) все как бы работает
; инициализция переменных
.def ST1 = r24 ; Флаги передатчика приемника(нулевого №0):
.equ ST1_PAC_OK = 0 ; Флаг прием пакета ок
.equ ST1_STABLE = 1 ; Флаг устойчивого соединения по ( … )
.equ ST1_RXD_ERR = 2 ; Флаг ошибки приема пакета
.equ ST1_TXD_ERR = 3 ; Флаг ошибка передачи пакета
.equ ST1_RXD = 4 ; Флаг окончания приема данных
.equ ST1_RXD_OK = 5 ; Флаг приема блока ОК
.equ ST1_TXD = 6 ; Флаг окончания передачи данных
.equ ST1_TXD_OK = 7 ; Флаг передачи блока ОК
.def TMP_X = r16 ; буфер задержеки
.def TMP_Y = r17 ; буфер при запуске конфигураций
.def TMP_D = r18 ; буфер коротких процессов (прерыв) если нехват то как ТМР_4
.def TMP_1 = r19 ; буфер данных не пересекается с конфигурацией
.def TMP_2 = r20 ; буфер данных не пересекается с конфигурацией
.def TMP_3 = r21 ; буфер данных не пересекается с конфигурацией
;————————————————————————————
; инициализация UART
ldi TMP_Y,0xA0 ; загружаем во временный регистр младший байт
sts UBRR1L, TMP_Y
ldi TMP_Y,0×01 ; загружаем во временный регистр старший байт
sts UBRR1H,TMP_Y
ldi TMP_Y,0×00
sts UCSR1A,TMP_Y
ldi TMP_Y,0×88 ;(1<<RXEN1)|(0<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
ldi TMP_Y,0×86 ;(1<<UMSEL11)|(1<<UCSZ11)|(1<<UCSZ10)
sts UCSR1C,TMP_Y
sbr ST1,S_BIT4 ; прием ЗАПРЕЩЕН изначально
;………………………
main:
rcall REREDACHA
rcall OUT_DATA
rcall AUDIT_ANSWER
rjmp main
;————————————————————
REREDACHA:
sbrs ST1, ST1_RXD
rjmp EXIT_REREDACHA
rjmp COMANDA_TXD ; п/п подготовки данных для передачи в ней шифруем данные кодом Мончестера и устанавливаем sbr ST1,S_BIT6
EXIT_REREDACHA:
ret
;————————————————————-
//*************************************************************************************
// Передача данных
//*************************************************************************************
OUT_DATA:
sbrs ST1,ST1_TXD ; проверка оканчания передачи
rjmp EXIT_OUT_DATA
//———-ПРОВЕРКА КОЛИЧЕСТВА ПЕРЕДАЧ———————————————-
REREDACHA_KOL:
lds TMP_1,CountTXD
cli
cpi TMP_1,KOL_TXD
brlo START_TXD_
sei
rjmp REREDACHA_KOL_OK
START_TXD_:
rjmp START_TXD
//———-ПЕРЕДАЧА ОКОНЧЕНА—————————————————-
REREDACHA_KOL_OK:
//———РАЗРЕШАЕМ ПРИЕМ——————————————————
cli
ldi TMP_Y,0×90 ;(1<<RXEN1)|(1<<RXCIE1)|(0<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
sei
//——————————————
cbr ST1,S_BIT4
cbr ST1,S_BIT6
//———ЗАПУСКАЕМ ВРЕМЯ ДЛЯ ОЖИДАНИЯ ПОВТОРНОЙ ПЕРЕДАЧИ—————————————
NUMBER_ZERO TimeANSWER_L, TimeANSWER_M, TimeANSWER_H
MACROS_NUMBER T_N_ANSWER_L,T_N_ANSWER_M,T_N_ANSWER_H,TimeANSWER
TRANSVER_NUMBER TimeANSWER_L, TimeANSWER_M, TimeANSWER_H
rjmp EXIT_OUT_DATA
//—————НАЧАЛО ПЕРЕДАЧИ—————————————————
START_TXD:
sei
//—————ПЕРЕДАЧА ДАННЫХ—————————————————-
UART_SNT:
sei
//————ЗАДЕРЖКА ВРЕМЕНИ НА ПЕРЕДАЧУ——————————————
lds TMP_1,Time10ms
cli
cpi TMP_1,ZERO
brne DELAY_10_
sei
rjmp UART_OUT_
DELAY_10_:
sei
DELAY Time10ms_L, Time10ms_M, Time10ms_H,Time10ms
rjmp EXIT_OUT_DATA
UART_OUT_:
rcall GO_10msec_
lds TMP_3, CountBateTXD
cli
cpi TMP_3,ZERO
breq ADR_5
cpi TMP_3,1
breq ADR_6
cpi TMP_3,2
breq ADR_7
cpi TMP_3,4
breq ADR_8
sei
clr TMP_3
sts CountBateTXD, TMP_3
rjmp EXIT_OUT_DATA
//———————————————————————————
ADR_5:
sei
ldi ZH,high(ADR_5_TXD) ; загрузка адреса
ldi ZL,low(ADR_5_TXD) ; загружаем адрес
ld TMP_2,Z ; увеличиваем значение адр на 1
rjmp UART_OUT
ADR_6:
sei
ldi ZH,high(ADR_6_TXD) ; загрузка адреса
ldi ZL,low(ADR_6_TXD) ; загружаем адрес
ld TMP_2,Z ; увеличиваем значение адр на 1
rjmp UART_OUT
ADR_7:
sei
ldi ZH,high(ADR_7_TXD) ; загрузка адреса
ldi ZL,low(ADR_7_TXD) ; загружаем адрес
ld TMP_2,Z ; увеличиваем значение адр на 1
rjmp UART_OUT
ADR_8:
sei
ldi ZH,high(ADR_8_TXD) ; загрузка адреса
ldi ZL,low(ADR_8_TXD) ; загружаем адрес
ld TMP_2,Z ; увеличиваем значение адр на 1
rjmp UART_OUT
//———————————————————————————
UART_OUT:
lds TMP_1,UCSR1A
sbrs TMP_1,N_BIT5 ; UDRE1
rjmp UART_OUT
sts UDR1,TMP_2 ;
lds TMP_3, CountBateTXD
inc TMP_3 ; разрешаем передачу следующего байта
sts CountBateTXD,TMP_3 ; сохранем содержимое регистра в переменной
lds TMP_3, CountTXD
inc TMP_3 ; разрешаем передачу следующего байта
sts CountTXD,TMP_3 ; сохранем содержимое регистра в переменной
rjmp EXIT_OUT_DATA
//———————————————————————————
GO_10msec_:
NUMBER_ZERO Time10ms_L, Time10ms_M, Time10ms_H
MACROS_NUMBER T_N_10ms_L,T_N_10ms_M,T_N_10ms_H,Time10ms
TRANSVER_NUMBER Time10ms_L, Time10ms_M, Time10ms_H
ret
//———ВЫХОД————————————————————————
EXIT_OUT_DATA:
ret
Первая передача проходт все ок и ответная часть присылает ответ который распознаеться, но повторную передачу не как не могу организовать
Допустим что от ответной части не пришла команда, а время ожидания на ответ истекло
посылаем повторно
//*******************************************************************************
// п/п ПРОВЕРКА ВРЕМИНИ НА ОТВЕТ
//*******************************************************************************
AUDIT_ANSWER:
//——-ПРОВЕРКА РАЗРЕШЕН ПРИЕМ——————————————
sbrc ST1,ST1_RXD
rjmp EXIT_AUDIT_ANSWER
//——-ПРОВЕРКА ОКОНЧАНИ ВРЕМЕНИ ДОПУЩЕННОГО НА ОТВЕТ——————
DELAY TimeANSWER_L, TimeANSWER_M, TimeANSWER_H,TimeANSWER
lds TMP_1,TimeANSWER
cli
cpi TMP_1,ZERO
brne EXIT_AUDIT_ANSWER
sei
//——-Время ИСТЕКЛО——————————————————
sbr ST1,S_BIT4 ; прием ЗАПРЕЩЕН
//—————РАЗРЕШЕНИЕ ПЕРЕДАЧИ—————————————————
;!!!! Вот тут на асцилографе нет передачи но уровень ТХD устанавиливаеться в 1
cli
ldi TMP_Y,0×88 ;(1<<RXEN1)|(0<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
sei
//————————————————————————————
clr TMP_1
sts CountTXD,TMP_1
sts TimeTXD,TMP_1
sts ComandaOldTXD,TMP_1
sts CountBateTXD,TMP_1
//——-ВЫХОД————————————————————
EXIT_AUDIT_ANSWER:
sei
ret
Проще самому заново написать чем в чужом коде разобраться.
По моему ты просто гдето намудрил. Вначале добейся чтобы у тебя данные летели потоком. Чтобы гарантировано видеть что уарт у тебя инициализирован правильно. Потом усложняй помаленьку.
Спасибо за ответ, данные летят потоком, и пачками, но вот после запрета передачи — разрешения приема и снова разрешения передачи они лететь не хотят ни как, а TXD (тыкаюсь на осцилографом) переходи в единицу
TxD переходит в единицу когда модуль не передает. Это нормально.
А если не запрещать передачу? Зачем?
Спасибо огромное!!! Все получилось, без запрета передчи, используя только заперт приема все работает!!!
А дай ка мне два кусочка кода сюда:
1) Где ты запрещаешь Передачу
2) где ты разрешаешь передачу.
Погляжу где там косяк.
Да в принципе все просто, но ведет себя по странному
при инициализации установлено
ldi TMP_Y,0×88 ;(1<<RXEN1)|(0<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
Далее после того как передача прошла n-кол-во раз выставляю запрет пеедачи/разрешение према
cli
ldi TMP_Y,0×90 ;(1<<RXEN1)|(0<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1) тут поставил 0х98 и все ОК
sts UCSR1B,TMP_Y
sei
Потом так как ответ не пришел овторяю передачу и переключаю UART
//————–РАЗРЕШЕНИЕ ПЕРЕДАЧИ—————————————————
;!!!! Вот тут на асцилографе нет передачи но уровень ТХD устанавиливаеться в 1
cli
ldi TMP_Y,0×88 ;(1<<RXEN1)|(0<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
sei
1) Ты разрешил Передачу, прием и запретил прерывания по передаче и приему
2) Ты разрешил Передачу, прием и запретил прерывания по передаче и приему
3) То же самое..
эээээ а где ты запрещаешь передачу? Или ты мне скинул тот вариант который работает?
Кстати, совет. Раз пишешь на ассемблере то рекомендую раскурить мою RTOS — с ней написание программ становится в десятки раз легче. Прошивка становится очень структурированной и ее легко понять, модернизировать, добавлять новые функции.
Порой даже до удивительного доходило — пишешь 6 часов прогу. Потом компилишь. Исправляешь все синтаксические ляпы и прога с первого прогона работает идеально, как задумано.
Извеняюсь в коментах ошибки
1. инит — разрешение приема запрет передачи (прерывание по приему разрешено)
ldi TMP_Y,0×88 ;(0<<RXEN1)|(1<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
2. передача закончалась
ldi TMP_Y,0×90 ;(1<<RXEN1)|(1<<RXCIE1)|(0<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
я тут щас написал в рабочем варианте
ldi TMP_Y,0×98 ;(1<<RXEN1)|(1<<RXCIE1)|(1<<TXEN1)|(0<<TXCIE1)
sts UCSR1B,TMP_Y
3. прием окончан
ldi TMP_Y,0×88 ;(0<<RXEN1)|(1<<RXCIE1)|(1<<TXEN1)|(0<>Раз пишешь на ассемблере то рекомендую раскурить мою RTOS
Re: Интересую вещь предлогаешь, что это где можно взять?
По идее должно работать, а почему не пашет.. хз, может там флаг какой не встает как надо, а у тебя на него циклится прога. Тут надо почитать внимательно даташит в том числе errata.
Вообще, по хорошему, проверять флаги уарта и на основании этого делать отправку моветон. Куда продуктивней слать по прерываниям все.
Т.е. у тебя етсь буффер. Ты туда сгружаешь свою посылку как есть, целиком. И засовываешь в UDR первый байт. Он отправляется и прерывание UDRE берет из буффера второй байт, потом третий пока все не кончится. А в конце всей этой бодяги у тебя выскочит прерывание TXCIE и чо нибудь еще сделает. Например загрузит в буффер следующую посылку если надо.
При этом прога выполняется сама по себе. Получается этакая многозадачность :)
Про RTOS написано в последних главах учебного курса AVR. Ну или поиском по сайту по слову RTOS
Еще где может быть косяк. У тебя если проверка на отправку сделана на бите TxC, а этот бит, ЕМНИП, снимается когда происходит уход на этот вектор. Либо вручную (что ты вряд ли делаешь). Но я вижу что ты там маниакально включаешь выключаешь глобальные прерывания (ИМХО перебор, Но тебе видней) и может получиться, что флаг просто зажует и твое условие переклинит.
Приемник GPS несет 42 байта по протоколу РС-232, дальше мая мега принимает их … Предположим мне для полного счастья нужно выбрать 5, 16, 18, 31 байты . Посоветуйте как это можно более рационально и правильно зделать? как отфильтровать эти байты и выкинуть остальные? Заранне спасибо!
П.С. Код этих байтов это время и координаты, то есть они все время меняються в большом интервале
Ловишь байты от начала пакета. И по счетчику выкидываешь те которые тебе не нужны. Как пакет весь собрал — счетчик сбрасываешь. Сделай все на прерываниях.
DI HALT, доброе время суток. Очень заинтересовал труд выложенный на твоём сайте. Нашел для себя много интересного и нового. Очень впечатлен твоими знаниями и оптимизмом и стермлением поделиться ими с другими. Как мне узнать твоё мыло? Хотел бы по теме взаимодействия м/контроллеров и COM портов посоветоваться. Моё мыло glass34(собака)mail(dot)ru. Заранее благодарю за ответ.
DI HALT, привет :) Решил разобраться с УАРТом (да и заодно закрепить уже познанное), но.. не работает! Код приведённый снизу (должен выводить на портД принятое), в качестве преобразователя — нечто втыкающиеся в USB (граунд к граунду на схеме, Тх к Rx на схеме), контроллер от внутреннего гена 8/8=1 МГц
Как не тыкал в терминалке — ничего не светит, не реагирует! (скорости и т.п. — совпадают)
Проверял лог. уровни на выходе преобразователя: 3.4 — высокий, 0.4 — низкий
Уже загнался искать ошибку, помоги пожалуйста!
Код:
.org 0×0000
rjmp RESET
.org 0×0007
rjmp USART0_RX
Reset:
ldi r16,RamEnd
out SPL, r16
ldi r16, 0b11111111
out ddrb, r16
ldi r16, (0<<pinD)
out ddrD, r16
ldi r16, (1<<SE) ;спящий режим разрешён
OUT MCUCR, R16
.equ XTAL = 1000000
.equ baudrate = 9600
.equ bauddivider = XTAL/(16*baudrate)-1
LDI R16, low(bauddivider)
OUT UBRRL,R16
LDI R16, high(bauddivider)
OUT UBRRH,R16
; LDI R16,0
; OUT UCSRA, R16
LDI R16, (1<<RXEN)|(1<<RXCIE)
OUT UCSRB, R16
LDI R16, (1<<7)|(1<<UCSZ0)|(1<<UCSZ1)
OUT UCSRC, R16
main:
rjmp main
USART0_RX:
lds r16, UDR
out portb, r16
reti
А какой проц?
Тини2313
НА кой черт тогда тебе команда LDS при выгрузке из UDR? Юзай IN R16, UDR и должно помочь :)
Хм.. наверное в панике кромсал код и пробовал всё подряд
Попробовал заменить на in — не работает.. :(
Предделитель убрал — не работает..
Буду пробовать с кварцем, может не синхронизируется
Поставил кварц, схема заработала (!) ровно один раз! Существует ли какая-либо последовательность подключения (например, сначала питание схемы, потом ком-порт, или наоборот)?
ЗЫ столкнулся с паразитным питанием от.. TxD :)) там всё (почти) время высокий уровень, и на питании контроллера — 2.5 в, чего достаточно ))
Добрый день.
Возникла необходимость передавать байты нескольким приемником одним передатчиком. Как это проще реализовать?
Заранее спасибо.
Уважаемый DI HALT!
Что-то эта тема очень туго идет. Много вопросов, много ответов, много комментариев, а народ все никак не может разобраться…
У меня вот проблемка с приемом-передачей пакетов в 2-14 байт. Ну не доходит до меня, как сделать буфер…
А слабо Вам написать универсальную библиотечку, как для LCD?
С Вашим талантом и уникальным умением объяснять доходчиво все вопросы сразу отпадут…
Библиотека не поможет Вам разобраться в проблеме.
На «С» НЕ надо и вникать в проблему- всё уже написано. НЕ надо делать никакой буфер- его уже сделали за Вас программисты CodeVision!!!
#include // Standard Input/Output functions — Великая Сила!!!
Да нет, лучше уж вникнуть. А то потом что пойдет не так и концов не найдешь.
DI HALT, у меня стала задача использовать интерфейс CAN с аврами. сложно ли это реализовать? пока не представляюю как. что нужно програмнно реализовать в авре для работы CAN интерфейса?
Смутно себе представляю что такое CAN и думаю AVR его не потянет, разве что с аппаратной поддержкой авр.
Тогда, может подскажите, какой интерфейс в авре можно использовать для ответственных команд? То есть интерфейс с помехоустойчивый, надежный и дальность приличная была. И еще я вот подумывал,можно ли RS-232 использовать в качестве канала которого оптоволокно? Тогда его дальность и помехоустойчивость увеличится. Правда ведь?
Сконвертить его в RS485 и вполне себе промышленное решение будет
Подскажите, пожалуйста, как сделть синхронный режим uart на примере tiny2313 или tiiny25?
Задача сделать температуро-устойивую телеметрию, а для кварца нет места на плате. Поэтому хочу использовать синхронизацию внешним сигналом.
Например для tiny25 пробую сделать программно и вырисовываются такой вариант:
Один из выводов конфигурируется как вход с подтяжкой. А другой как выход uart.
По изменению логического уровня на входе в процедуре прерывании передается бит из кадра UART.
Т.е если ко входу подключен внешний генератор на 19200 телеметрия есть, не подключен, телеметрии нету.
А как правильно сделать по науке?
ЕМНИП уарт может работать и в синхронном режиме. Правда там вроде как не дуплекс получается, а полудуплекс т.к. один провод синхронизация другой данные. Почитай даташит или Евстифеева.
Можешь сделать по SPI он от природы синхронный.
В чём разница между USART и UART? По спецификации, благодаря синхролинии как бы скорость можно больше поставить.
Ну, а если скорость не главное, есть ли ещё смысл добавлять сихронизацию?
В том что уарт в принципе не умеет в синхре работать. Вот и вся разница.
Подскажите плиз как програмно реализовать uart
вот только что хотел спросить почти то же самое: UART ведь один в контроллере. если надо два — то только программно? Ди, ты кодил программный UART? как посоветуешь это сделать?
На AVR нет, на С51 приходилось. Комментом ниже я дал ссылку на библиотеку ассемблерных исходников. Там же целых три вида софтверных уарта.
Обычно его на INT прерывании делают Т.е. чуем старт бит, запрещаем прерывание и начинаем по таймеру пропалывать (от poll-опрос) линию по бодам. Есть бит — 1, нет бита 0. Настройка таймера по бодрейту, число тыков опроса обычно хватает и одного на бит, но надежней несколько. АВР емнип каждый бит три раза проверяет.
UART может быть и больше максимум чтоя встречал 8 просто еслиб был специализованый МК… а так ставить монстра с сотней ножек когда просто нада 4 порта не очень охота…
кстати вот нашол:
http://depositfiles.com/files/qopdpg67j
и вобще советую: http://radiojurnals.xan.su/buki/mk.htm
Правда пока нет времени читать но завтра надеюсь почитаю… Если кто ещо знает книги по програмной реализации буду оч благодарен за ссылки… (Также оч интерисует мнение за против, подводные камни, грабли… а то и так тяжело асм ток 2 неделю изучаю:)
http://avr-asm.tripod.com/avr304.html
ну вот тебе софтверный усарт. Вообще на этом сайте дофига ассемблерных примеров.
>> LDI R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
error: Undefined symbol: URSEL
Судя по описанию он равен семёрке. Но и с ней ничего не работает — в терминале Putty я получаю кучу символов «-» (это горизонтальная линия, которыми в DOS’e рисовали рамки).
Кстати, HyperTerminal вообще не хочет работать, при замыкании Rx на Tx ничего в ответ не получает. Поэтому работают с Putty.
А ну так у тебя уарт чуток по другому инициализируется, раз у тебя URSEL не нашелся.
Какой мк?
tiny2313
Вот тебе инициализация для тиньки2313
Ни эта, ни та которая в даташите (собственно это почти одно и то же) ничего не изменяют — в терминал сыпятся эти чёрточки вместо изменяющихся символов (каждый цикл с задержками 1 сек. передаю R20, который каждый раз уменьшаю на 1).
Я уже подумываю, что проблема в MAX232-переходнике, но странно что при замыкании Rx-Тх я получаю байты обратно.
Так. а ты бит делителя частоты сбросил? У тебя она поди на 1МГц пашет :)
Ураааа. Наконец-то я сделал что-то, что работает :)
Большое спасибо за этот злосчастный CKDIV8 бит, я бы еще много времени потратил пока обнаружил его.
Имею в терминале периодически уменьшающийся R20, то есть ЧЩЭШЗЫЬВЖУТСРЯПОНМЛКЙИХГФЕДЦБАЮъчщэшзыьвжутсряпонмлкйихгфедцбаю©╬Ґ╪╩╨╧╦ЇІ╣ЄЁ╡╠╟╞╝ґ╛╚╙╘╗їі╔єё╒║═÷·²°⌡ ≥≤≈√•■⌠▓▒░▐▌█▄▀┼┴┬┤├┘└┐┌│~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:987654321
Еще раз спасибо :)
Сорри за отсутствие переносов, я не подумал что всё так разъедется
Так, теперь хочу и принимать байты. И снова проблемы :)
Во-первых, UCSRA & (1<<RXC) почему-то всегда 0. Всегда.
Во-вторых, прерывания не работают ни при получении, ни при отправке данных. Хотя я их разрешал при инициализации UART (OUTI UCSRB, 1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE). Может где-то еще надо глобально их разрешить каким-нибудь SEI? если даю команду SEI перед основным циклом программы, то данные через UART начинают идти с гигантской скоростью, я в терминале за полосой прокрутки не успеваю…
В-третьих, для создания обработчика прерывания на языке Си этого кода достаточно? больше ничего не надо?
ISR(USART_RXC_vect)
{
switch(UDR)
{
case ’1′: LED_PORT = 0<<LED1; break;
case ’0′: LED_PORT = 1<<LED1; break;
default: break;
};
};
Да надо глобально разрешить. SEI
то что у тебя данные полетели в усарт бесконтрольно это значит что утебя программа дала где то сбой.
Для си этого достаточно, но надо создать обработчики для всех разршенных прерываний иначе будет краш. Либо не разрешать то что ты не испльзуешь.
Но по умолчанию ведь всё запрещено? или только глобальные запрещены, «а так» некоторые разрешены?
По дефолту запрещено вообще все. Разрешаешь вручную по одному ну и глобальные тоже.
Как присвоить переменной значение, из компа в МК через UART ??????
Настроить USART
в прерывании по RX сделать чтение из регистра UDR и записать в нужную переменную
А как в терминале отправлять например А=10 так ?????
можна фрагмент программы пожалуйста ….
Вот часть кода
LDI XH,high(String) ; некий буфер, из который потом будет отправляться по UART
LDI XL,low(String)
ST X+,R15 ; в регистах результат, заполняю String
ST X+,R14
ST X+,R13
ST X+,R16
ST X+,R11
LDI R19,0x0A ; признак конца буфера
ST X+,R19
LDI XH,high(String)
LDI XL,low(String) ;ставлю указатель на начало буфера
LD R21,X
OUT UDR, R21 ; вручную забрасываю в регистр первый элемент буфера на отправку
SBI UCSRB,UDRIE ; установить бит в РВВ ; разрешить прерывания
Смотрю всё в Студии в режиме отладки. После предпоследней команды UDR обнуляется (что вроде логично, так как данные из него перебросились в сдвиговый регистр), соответственно возник флаг опустошения буфера, но прерывания пока нет, так как они ещё запрещены.
Последней командой я их как раз и разрешаю. И как положено возникает прерывание.
_UDREempt: LD R21,X+ ; в этой строчке не совсем правильно, будет повтор первого символа, плохо что нет LD R21,+X :)
CPI R21, 0x0A
BRNE _snt
OUT UDR, R21
CBI UCSRB,UDRIE ; очистить бит в РВВ; запретить прерывания по опустошению
RETI
_snt: OUT UDR, R21
RETI
Но вот в чём вопрос: после _snt: OUT UDR, R21 UDR тутже опять обнуляется. Почему? Ведь ещё первый байт не ушёл. На скорости 9600 (у меня) он будет уходить чуть более 1мс, почему он обнулился, если сдвиговый регистр ещё занят, пихать некуда. Хотя Студия показывает что UDRE ещё 0, т.е. не пуст. Может это всего лишь особенности отладки Студии. Следующий символ отправляется вроде бы правильно — через 1мс, тоже по появлению флага опустошения.
И ещё вопрос — насколько правильно или оптимально реализованн процесс вывода в UART с использование прерываний? В этом моём случае
Скорей всего это прикол студии. А по прерываниям кормить буффер правильно.
Я сломал голову.
В AVR studio регистр UBRRH меняется вместе с UCSRC.
Бит в URSEL не помогает.
Это баг симулятора?
//uart init
UBRRH=0b00000000;
//всё хорошо
UBRRL=0b01100111;
//всё хорошо
UCSRB=0b00011000;
//всё хорошо
UCSRC=0b10000110;
//всё плохо!!! UBBRH тоже изменил своё значение
Я бы всё простил, но при загрузке байта в UDR — флаг UDRE не падает.
И мир во всём мире не наступает.
Что делать?
Дай весь проект я погляжу.
В проекте ничего больше нет.
Только #include
Это я решил разобраться с передачей через UART.
Микроконтроллер ATmega8.
По поводу регистров UBRRH и UCSRC в студии. Сам долго не вкуривал тему, менял очередность и так и так. А он писал в оба регистра одинаковое значение (даже при явном указании URSEL 1 или 0). Выкурил даташит (на мегу16) проверил кода от DI, а вкумекал, только тогда, когда по совету DI выкурил инклюдник — там четко написано что UBRRH и UCSRC имеют адрес $20, а в коменте написано «; Note! UCSRC equals UBRRH», что не противоречит даташиту. Главное при записи в UCSRC использовать бит URSEL=1 (как в примере DI). А в симуляторе студии — это баг, так как в новых МК эти регистры имеют разные адреса(а в старых МК регистра UBRRH вообще не было) то разработчики не парились по поводу обработки одного бита, тем более названия регистров берутся из инклюдника.
«Я бы всё простил, но при загрузке байта в UDR — флаг UDRE не падает.» у меня он тоже не сразу падает, а только после прохода следуующей команды.
Всем привет!
У меня ATMega8, фьюзы все заводские (т.е. работает она на частоте 1МГц).
К USART соединился кабелем на pl2303 (от какого-то сотового).
Результат пока: светодиод мигает 10 раз (показывает старт), потом на терминал (использую putty) валится мусор какой-то, т.е. как будто бы скорости не совпадают…
Код вот такой (вставил как есть):
/*
USART Test
*/
#include
#include
#include
// Define baud rate
#define XTAL 1000000UL
#define BAUDRATE 9600UL
#define BAUDDIVIDER (XTAL / (BAUDRATE * 16) — 1)
void USART_Init(void)
{
// Set baud rate
UBRRH = (uint8_t)(BAUDDIVIDER>>8);
UBRRL = (uint8_t)BAUDDIVIDER;
// ?
UCSRA = 0;
// Enable receiver and transmitter and disable interrupts
UCSRB = (1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<TXCIE);
// Set frame format to 8 data bits, no parity, 1 stop bit
UCSRC = (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1);
}
void USART_Send(uint8_t u8Data)
{
while((UCSRA & (1<<UDRE)) == 0);
UDR = u8Data;
}
uint8_t USART_Recv(void)
{
while((UCSRA & (1<<RXC)) == 0);
return UDR;
}
void main(void)
{
DDRB=0×01;
// Show that we’re started (blink 10 times)
for(uint8_t i=0; i<10; i++)
{
PORTB=(0<<PB0);
_delay_ms(300);
PORTB=(1<<PB0);
_delay_ms(300);
}
// Initialise USART
USART_Init();
// Send forever
for(;;)
{
USART_Send(‘T’);
USART_Send(‘E’);
USART_Send(‘S’);
USART_Send(‘T’);
USART_Send(0x0D);
USART_Send(0x0A);
}
/*
// Repeat indefinitely
for(;;)
{
// Echo received characters
u8Data = USART_vReceiveByte();
USART_vSendByte(u8Data);
}
*/
}
Где может быть ошибка?
P.S. И главное что странно — этот код _почти_ работает, т.е. «затык» где-то совсем в малом… :(
Выглядит все верно. А точно скорость 1мгц? И еще мне не очень нравится приведение байта при заполнении UBRR, попробуй там вручную циферки прописать.
Ура! Всё заработало!
Кабель был просто глючный.
Вот видео: http://www.youtube.com/watch?v=yqvrzfnHuWI
Заработал кабель от Pantech на чипе OTI (там прям на платке написаны не номерки, а названия: GND, Tx, Rx и т.д.)
Кабель который НЕ заработал называется GT2303 (сделан на Prolific PL2303), к нему припаяно 4 проводка (которые к телефону). На плате GT2303 так (номера прям на плате проставлены — на «телефонной» стороне): 6-белый (похоже на VCC, во всяком случае МК от него и зелёного запитывается), 3-синий, 4-красный, 11-зелёный(похоже на GND). Может кто знает что это за зверь? Работает 50/50, хотя винда определяет его всегда.
DI HALT, а про использование ATMega8 напрямую с USB статья будет? ;)
И ещё интересно потянет ли ATMega8 ethernet?
Кабель GT2303 (на pl2303) запустил! :)
Если кому интересно — вот его точная распайка: http://forums.drom.ru/attachment.php?attachmentid=671346&stc=1&d=1254733592
Ещё интересный момент: putty почему-то «падает» через несколько секунд, а вот Hyper Terminal отлично работает (настройки идентичны) — кто-нибудь знает почему?
Теперь всё нормально — см. ниже совет по частоте атмеги
ВНИМАНИЕ!
Чтоб на ATMega8-16PU на внутреннем осцилляторе USART работал _СТАБИЛЬНО_ — надо поставить 8МГц!!!
Проверил опытным путём — все глюки полностью исчезли!
фьюзы: 0xD9 и 0xE4(для 8МГц, по умолчанию для 1МГц — 0xE1)
Насчёт переходника — я использовал от сотовых, что является, не побоюсь этого слова, лотереей :)))
Наткнулся на интересный проект: http://www.recursion.jp/avrcdc/ — там на ATTiny45-20 делается такой переходник — паять её проще, чем max232 IMHO :)
Привет.
Подскажите каким образом можно подключить несколько датчиков, имеющих выход RS485, к одному контроллеру ATMega.
Перечитываю первые посты после статьи и не очень-то доходит. :)
«Вешаем прерывание по UDRЕ которое пропихивает все данные из буфера в UDR, а когда буфер опустошится само себя отключает»
Момент «…само себя отключает» это как — это само собой происходит, или в обработчике проверка на опустошение вышеуказанного буфера?
И что подразумевает под собой прерывание по завершению передачи, включаемое битом TXCIE? Т.е. когда у нас в сдвиговом регистре есть байт, который в данный момент отправляется и в UDR уже помещен следующий, последний из буфера, на отправку (который по хорошему должен быть помещен по перыванию UDRE) и после того как этот последний байт из UDR перейдет в сдвиговый регистр и полностью отправится, а в UDR уже ничего не будет, вот тогда и возникнет прерывание по завершению передачи? Правильно я понимаю?
Просто никак не могу придумать, как сделать так что-бы не возникало никаких прерываний после отправки последнего байта и не делать запрет прерываний по опустошению UDR или окончания передачи (если такое возможно). Приходит в голову толко проверка последний ли символ или нет и запрещать перывания, чтобы не попадать в обработчик лишний раз
Именно в обработчике мы проверяем по быстрому буффер и если он пуст то запрещаем прерывание UDRE и выходим. Все, на этом передача со стороны софта оканчиается (но продолжается на уровне железа — усарт все еще шлет байт из сдвигового регистра).
Дальше у нас буффер пуст, сдвиговый регистр тоже опустел и вылетает TXC — полное окончание всей передачи.
В инициализации USART — может не URSEL , а UMSEL, и не 1 а 0? Режим-то асинхронный isnt it?
«Самый прикол тут это бит селектора URSEL дело в том, что по неизвестной причине создаетели решили сэкономить байт адреса и разместили регистры UCSRC и UBRRH в одной адресном пространстве. А как же определять куда записать? А по старшему биту! Поясню на примере. Если мы записываем число у которого седьмой бит равен 1, то оно попадет в UCSRC, а если 0 то UBRRH.»
Вроде там просто выбор синхронный-асинхронный. А выбор куда записывать может типа раньше было , ну типа в более ранних моделях? Воще-то в мануале на например 2313 UMSEL просто селектор синхронный-асинхронный, а в UCSRC 7 бит типа просто зарезервирован, ну вроде типа так. Э?
Не путай с UMSEL (Uart Mode Selectror). URSEL (Uart Register Selecter) это бит селектора в какой регистр засылать. Причем этот фокус далеко не на всех моделях AVR а чеерз раз (обычно в старых аврках вроде Меги8 он есть) :)
Здравствуйте. Подскажите пожалуйста, как, используя МК, организовать прием/передачу от/к 16 независимых источников. Заранее благодарен.
по уарту это будет сложновато. Т.к. в уарте нет никакой поддержки адресов и коллизий или прочих механизмов разделения источников. Разве что Token Ring организовать с жестким разделением. Тебе лучше подумать в сторону iic
Спасибо за помощь! Но возник вопрос!: Мне надо реализовать модуль сопряжения CPU (CompactPCI) с 16 независимыми станциями (RS422). Я думаю ставить по контроллеру с УАРТ на прием/передачу в сторону станций, они (контроллеры) должны быть связаны с главн.контроллером, который принимает информацию от CPU, вопрос — подойдет ли для связи контроллеров IIC (я прочитал, что у нее низкая пропускная способность и практически не используется в ПК)? Что Вы скажите про SPI? и вообще в том ли направлении двигаюсь?
У IIC скорость 100кбит секунду. Зато есть адресация, разгребание коллизий и много плюшек. Она заточена на работу с множеством приемников. Но на компе ты ее не найдешь, придется делать адаптер.
SPI работает очень быстро, но у ней три линии + по линии разрешения на КАЖДЫЙ приемник. Т.е. у тебя будет 19 проводов тянутся :)
Объясните, пожалуйста, подробнее что значит «Но на компе ты ее не найдешь, придется делать адаптер»?
Переверни комп задницей к себе. Ты видишь там гнездо i2c ? Вот и я не вижу. А тебе же надо к компу цеплять?
DI HALT, подскажи, как борется с коллизиями SPI? посоветуй литературу или ссылки о нем, пожалуйста.
На SPI не возможны коллизии в принципе.
DI HALT, возможно ли по SPI соединить 4 равноправных микроконтроллера с одним общим (топология «звезда») каждый может передавать и принимать информацию. (каждый может быть и ведущим и ведомым)?
Только если от каждого к каждому будет идти провод разрешения работы. Но это проводов убиться. У SPI же нет никакой адресации и системы разрешения коллизий. Тут коллизия вызывает сгорание кого либо :)
Спасибо за помощь! Поздравляю с переездом! DI HALT, помоги разобраться, предположим МК имеет 8 УСАРТ интерфейсов (Хмега), они подключены к 8 независимым передатчикам, у меня возник вопрос — предположим УСАРТ1 принял инф-ю, сработало прерывание и программа ушла на его обработку, а если в это время остальные УСАРТ принимают инф-ю (много байт), буфер всего 2 байта, не потеряются ли первые принятые байты пока обрабатывается прерывание УСАРТ1. Как управлять всеми 8 УСАРТ, чтобы данные не потерялись и не было застоя?
Прерывание должно быть очень быстрым. Т.е. хапнул байт из аппаратного буффера и перекинул его в программный буффер. Вышел. На все про все около 10тактов, если на ассемблере писать. Тогда ничо не потеряешь.
Ай-ай-яй… Что действительно все так плохо?
А если ОЧЕНЬ нужно. Ну например 16 устройств на расстоянии 15-30 метров между ними (общая длинна линии 370 метров).
А что такое «Token Ring»?
RS485 или толстый кокс. Что такое токен ринг? Загугли. В двух словах это не опишешь.
«А что такое “Token Ring”?»
——————————
Рекомендую книгу Л.Райс Эксперименты с локальными сетями микро-ЭВМ. Издательство Мир 1990. 268стр.
Там большая часть книги как раз про “Token Ring”, а в начале — коротко про другие методы последовательной передачи данных (Манчестер, NRZ, RS232). Написано очень хорошо.
Спасибо, хорошая книга, наверное… В сети не могу найти.
Основные принципы понял. Нужны детали…
Здравствуйте, подскажите пожалуйсто!
Надо прицепить мою мегу16 к компу через USART. Для начала решил разобраться с ним в AVR Studio. Вот мой код:
USART_Init:
ldi temp, 0×00 ; Set baud rate 9600
out UBRRH, temp
ldi temp, 0x1A
out UBRRL, temp
ldi temp, (1<<RXEN) | (1<<TXEN)
out UCSRB,temp ; прием и передача разрешены
ldi temp, (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0) ; длина — 8 бит
out UCSRC,temp
ret
USART_Receive:
sbis UCSRA, RXC
rjmp USART_Receive
in temp, UDR
ret
Значит, как только курсор остнавливается на метке USART_Receive: загоняю я в регистр UDR байт, предпологая, что он там останется, пока не поставлю флаг RXC. А он(UDR) на следующей команде просто сбрасывается в 0 и этот ноль идет в temp.
Ловить надо по прервыаниям. В реале, кстати, твой код должен заработать.
Да, проверил в Proteus 7.4 вроде работает. А на самом нужно сделать так, чтобы контроллер из всех полученных байтов фильтровал только нужный ему ( у меня это 1), как только его словит на PC5 загорается светодиод. А остальные байты пусть пока засовывает в какой-нибудь рон не изменяя их. В Протеусе на виртуальном терминале от генератора байтов и в самом деле передаются единицы, а вот на RXD приходит какая-то муть, все что угодно, кроме 1. А еще он ругается что у меня ошибка «Error Frame». Не могу понять почему: кадр 8 бит 1 стоп, без четности, от внутреннего генератора, в протеусе принимает биты от генератора HDL через MAX232. Вот мой код, вам на расскритиковку. Подскажите pls, заранее благодарен))
.include «C:\Program Files\Atmel\AVR Tools\AvrAssembler\Appnotes\m16def.inc»
.equ baudrate = 9600
.list
.def temp = R16
.def byte_res = R17
.def byte_count = R18
.def t0 = R19
.cseg
.org 0×0000
jmp main
.org $002 ;External Interrupt0 Vector Address
reti
.org $004 ;External Interrupt1 Vector Address
reti
.org $006 ;Output Compare2 Interrupt Vector Address
reti
.org $008 ;Overflow2 Interrupt Vector Address
reti
.org $00A ;Input Capture1 Interrupt Vector Address
reti
.org $00C ;Output Compare1A Interrupt Vector Address
reti
.org $00E ;Output Compare1B Interrupt Vector Address
reti
.org $010 ;Overflow1 Interrupt Vector Address
reti
.org $012 ;Overflow0 Interrupt Vector Address
reti
.org $014 ;SPI Interrupt Vector Address
reti
.org $016 ;UART Receive Complete Interrupt Vector Address
rjmp USART_RXC
.org $018 ;UART Data Register Empty Interrupt Vector Address
reti
.org $01A ;UART Transmit Complete Interrupt Vector Address
reti
.org $01C ;ADC Interrupt Vector Address
reti
.org $01E ;EEPROM Interrupt Vector Address
reti
.org $020 ;Analog Comparator Interrupt Vector Address
reti
.org $022 ;Irq. vector address for Two-Wire Interface
reti
.org $024 ;External Interrupt2 Vector Address
reti
.org $026 ;Output Compare0 Interrupt Vector Address
reti
.org $028 ;Store Program Memory Ready Interrupt Vector Address
reti
.org $02A
main:
ldi temp, 0xff
out DDRC, temp
ldi temp, 0×00
out PORTC, temp
ldi temp,high(RAMEND) ; инициализация стека
out SPH,temp
ldi temp,low(RAMEND)
out SPL,temp
uart_init:
LDI temp, 0×00
OUT UBRRL,temp
LDI temp, 0x0C
OUT UBRRH,temp
LDI temp, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(1<<UDRIE)
; Прерывания запрещены, прием-передача разрешен.
OUT UCSRB, temp ; ; Формат кадра — 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор
ldi temp,(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ0)
out UCSRC,temp
sei
T: ; замкнутый цикл
rjmp T
;Обработка прерывания по событию «ПРИЕМ БАЙТА» через USART
USART_RXC:
in temp,UDR ;Сохраняем полученный символ (Чтение порта)
cbi UCSRB, RXCIE ;Запрещаем прерывание
sbis UCSRA,FE ;Проверяем на наличие ошибки кадра
rjmp T
cpi temp, 1
breq LED
rcall SendByte ;Отладка
SBI UCSRB, RXCIE
SBI UCSRB, UDRIE ; Разрешаем прерывание
reti
SendByte: ;Передача символа на ПК
sbis UCSRA,UDRE ;Пропустить следующую команду если бит в порту сброшен (регистр не пуст)
rjmp SendByte ;Ожидаем освобождения буфера передачи
out UDR,temp ;Передаем символ
ret
LED:
sbi PORTC, 0×05
ret
Зачем ты разрешаешь прерывания по передаче если не используешь его?
Это не обработчик прерывания, это какой то пиздец:
Нарушены все правила какие только можно нарушить. Регистры не сохраняются в стеке, циклы ожидания в обработчиках. Ну кто так делает? У тебя программу срывает.
Плюс какого хрена вот это:
breq LED
ушел через JMP
LED:
sbi PORTC, 0×05
ret
вернулся через RET и куда вернулся? Вывалился из обработчика прерываний, но с запрещенными глобально прерываниями.
Программу в AVR Studio трассировал? Сразу скажу, что нет. Т.к. такие ошибки вылавливаются при ПЕРВОМ же прогоне трассировщика. И смысл было без трассировки дальше голову ломать?
М-да. Согласен, Di HALT, затупил я))))). Взял куски кодов, сдесь имеющиеся, слепил все тупо.
Код я переделал, работает по-ходу, но не совсем правильно. Дело в том, что когда у меня байт (причем любой) приходит с UDR в TEMP, в TEMPе, 5 и 6 разряды устанавливаются в 1. Поэтому, когда сравниваю с константой, приходится писать не 3, а 51. Что это, глюк протеуса или я опять чего-то напортачил??
А еще, чуть не забыл, у меня вопрос, по поводу Протеуса. Собрал я в нем схемку для передачи данных: RS-232 — MAX232 — ATmega16. Когда начал передовать байты нога MAXа засветилась желтым цветом, мол ошибка. Залез на один форум, там сказали, что надо еще один MAX последовательно прицепить. Попробовал — заработало! А как в реале, на железе, нужна ли вторая MAX?
А вот тут должно работать четко. Т.е. что пришло в UDR то и должно попасть в темп.
Причины могут быть следующие:
Ты выставил неправильно скорость/частоту/параметры работы уарта и у тебя в UDR приходит что то что уарт принимает за 51. Мог затупить с тактовой частотой виртуального МК в протеусе.
2. Где то у тебя темп портится в прерывании, а ты это недофиксил. Опять же, в прерывании у тебя грубейшая ошибка — ты не сохраняешь регистры в стек. В этом примере прокатит, т.к. у тебя нет никакого действия фоном
Y: rjmp Y
только тупой цикл, но в другой программе, с более содержательынм майном у тебя эти приколы очень быстро вылезут на поверхность.
В железе нужен 1мах232 , а в протеусе для связи с терминалом он не нужен вообще.
DI HALT, по пункту 2. Я так понимаю, речь идет о сохранении в стеке регистра SREG? Я не совсем понимаю для чего его там сохранять, всегда думал, что стек служит только для сохранения текущего адреса процессора, чтобы тот вернулся туда же, после выполнения прерывания, откуда его вызвали. А как примерно должен выглядеть мой кусок обработчика прерываний после сохранения в стеке регистра?
Не только срег, но и все используемые регистры.
Перечитай АВР. Учебный курс. С самого начала (там переписаны заново почти все статьи) и поймешь как работает стек, зачем сохранять регистры и так далее.
Дабро. Огромное спасибо за помощь))!
Помогите понять проблему пожалуйста.
Использую обмен данными по USART с COM портом ПК. На компьюторе пробовал через прграммы Terminl by bray, Hypper Terminal и даже написал на C# программу работы с КОМ портом.. Результат тот — же :(
Вот код:
В итоге: При запуске устройства — исправно приходят в терминал надпись Hello 12345
если я через терминал отправлю ОДИН! символ.. он исправно придет.
Если отправлю несколько — приходит белиберда. Если внутри AddData поставю таймаут на 20-30 мс, то и несколько символов приходят отлично. В чем может быть загвоздка? почему если налету получать символ и пересылать эхом его назад — УАРТ не успевает? :(
Спасибо. 3-й день бьюсь (
У тебя, как понял, буффер который выгребается и заполняется по прерываниям.
У тебя не может буффер схлопываться? Т.е. следующий байт пытается в него записаться когда он еще не отправлен?
Проблема тут не аппаратная. Если сделать на ассемблере то код вида
в обработчике по приему дает отличное эхо и ничего не цепляется, несмотря на то что тут всего две команды и выполняется очень быстро.
А ты про какой буфер? УАртовский или мой (в коде buffer)?
Он циклический.. в данный момент 64 байта размер. на Recive я записываю в массив(буффер) байт из UDR. и включаю выключенное прерывание UDRIE. Соотв на прерывание пустого буфера байт может без проблем достаться.
В коде видно ATOMIC блоки… я пробовал и с ними.. чтоб небыло конфликтов.. все одно и то же.
Если я (как видно в коде) при инициализации заполню свой буфер батами, потом запущу прерывания, то данные Hello 12345 уйдут без ошибок..но проблема выходи когда мы читаем байт — пишем в бкфер.. на следущем прерывании пустого буфера данных я считываю из массива свой байт и помещаю в UDR. и какая же тут может быть ошибка? помещение в массив происходит в прерывании приема.. я правильно понимаю что оно не прервется другим прерыванием пока не закончится? SIGNAL вроде бы так работает.. соотв. байт в мой массив запишется 100%.. и точно так же при отправке… в любом случае я пробовал в прерываниях писать cli() , sei()
Про твой. Т.к. байт должен успеть приняться. Как минимум два символа. замыль мне проект целиком я в студии погоняю dihalt@dihalt.ru
Блин, только на работу причалил. Проект дома. Писал в AVR studio. Собственно код в первом посте — это все. По инклуднику можно увидеть что это ATMega162
проц работает на 16 Мгц(проверено , скорость такая).
Ед. что можно тут удалить это обработчик прерывания таймера и BtnSwitchInit(); Эта часть отдельная… она ловит нажатие кнопки с обработкой пржинистости :) механического контакта..
а дефаны эти юзал
#define BV(x) (1<<x)
#define sbi(port, bit) (port) |= (1 << (bit))
#define cbi(port, bit) (port) &= ~(1 << (bit))
Да мне просто влом под это дело проект создавать, зависимости прописывать :)
Конечно. Я понимаю. Вечером замылю. Спасибо.
Скинул на почту..
З.Ы. 5 утра? о_О DI Halt тебе не спиться? :)
Ты спроси лучше во сколько я лег :)
Ой. Сорри за выравнивание кода :( так вставилось :(
Люди помогите.
Вот код, где ошибка??? Чт оне так???
Весь вечер убил :(
.include = «m8515def.inc»
; ATmega8535
; 8MHz
.DSEG
.equ XTAL = 8000000
.equ baudrate = 9600
.equ bauddivider = XTAL/(16*baudrate)-1
.equ CS = PB4
.equ MOSI = PB5
.equ MISO = PB6
.equ SCK = PB7
.equ LabelSTART = 0×60
.equ LabelEND = 0×73
.CSEG
;Èíèöèàëèçàöèÿ ÌÊ
.ORG 0×000
RJMP Reset ;Ïðîïóñêàåì âåêòîðà è ïåðåõîäèì íà èíèöèàëèçàöèþ ñòåêà
.ORG $001
RETI ; (INT0) External Interrupt Request 0
.ORG $002
RETI ; (INT1) External Interrupt Request 1
.ORG $003
RETI ; (TIMER2 COMP) Timer/Counter2 Compare Match
.ORG $004
RETI ; (TIMER2 OVF) Timer/Counter2 Overflow
.ORG $005
RETI ; (TIMER1 CAPT) Timer/Counter1 Capture Event
.ORG $006
RETI ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
.ORG $007
RETI ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
.ORG $008
RETI ; (TIMER1 OVF) Timer/Counter1 Overflow
.ORG $009
RETI ; (TIMER0 OVF) Timer/Counter0 Overflow
.ORG $00A
RETI ; (SPI,STC) Serial Transfer Complete
.ORG $00B
RETI ; (USART,RXC) USART, Rx Complete
.ORG $00C
RETI ; (USART,UDRE) USART Data Register Empty
.ORG $00D
RETI ; (USART,TXC) USART, Tx Complete
.ORG $00E
RETI ; (ADC) ADC Conversion Complete
.ORG $00F
RETI ; (EE_RDY) EEPROM Ready
.ORG $010
RETI ; (ANA_COMP) Analog Comparator
.ORG $012
RETI ; (SPM_RDY) Store Program Memory Ready
.ORG INT_VECTORS_SIZE
; Êîíåö òàáëèöû ïðåðûâàíèé
Reset:
;Î÷èñòêà ÎÇÓ
RAM_Flush: LDI ZL,Low(SRAM_START)
LDI ZH,High(SRAM_START)
CLR R16
Flush: ST Z+,R16
CPI ZH,High(RAMEND)
BRNE Flush
CPI ZL,Low(RAMEND)
BRNE Flush
;Î÷èñòêà âñåõ ðåãèñòðîâ
CLR R0
CLR R1
CLR R2
CLR R3
CLR R4
CLR R5
CLR R6
CLR R7
CLR R8
CLR R9
CLR R10
CLR R11
CLR R12
CLR R13
CLR R14
CLR R15
CLR R16
CLR R17
CLR R18
CLR R19
CLR R20
CLR R21
CLR R22
CLR R23
CLR R24
CLR R25
CLR R26
CLR R27
CLR R28
CLR R29
CLR R30
CLR R31
;Èíèöèàëèçàöèÿ ñòåêà
STACK: LDI R16,Low(RAMEND) ; Çàïèñûâàåì äíî ÎÇÓ
OUT SPL,R16 ; â ìëàäøèé ðåãèñòð
LDI R16,High(RAMEND) ; Çàïèñûâàåì äíî â ÎÇÓ
OUT SPH,R16 ; â ñòàðøèé ðåãèñòð
CLR R16
;Çàïèñü ïðèâåòñòâèÿ â SRAM
Data:
LDI R16,’C’
STS 0×60,R16
LDI R16,’O’
STS 0×61,R16
LDI R16,’N’
STS 0×62,R16
LDI R16,’T’
STS 0×63,R16
LDI R16,’R’
STS 0×64,R16
LDI R16,’O’
STS 0×65,R16
LDI R16,’L’
STS 0×66,R16
LDI R16,’L’
STS 0×67,R16
LDI R16,’E’
STS 0×68,R16
LDI R16,’R’
STS 0×69,R16
LDI R16,’ ‘
STS 0x6A,R16
LDI R16,’H’
STS 0x6B,R16
LDI R16,’O’
STS 0x6C,R16
LDI R16,’N’
STS 0x6D,R16
LDI R16,’D’
STS 0x6E,R16
LDI R16,’A’
STS 0x6F,R16
LDI R16,’-’
STS 0×70,R16
LDI R16,’B’
STS 0×71,R16
LDI R16,’U’
STS 0×72,R16
LDI R16,’S’
STS 0×73,R16
RJMP SENT
;Èíèöèàëèçàöèÿ RS-232
UART_Init:
; Set baud rate
LDI R16, low(bauddivider)
OUT UBRRL, r16
LDI R16, high(bauddivider)
OUT UBRRH, r16
;Ïðåðûâàíèÿ çàïðåùåíû, ïðèåì-ïåðåäà÷à ðàçðåøåí.
LDI r16, (1<<RXEN)|(1<<TXEN)
OUT UCSRB,r16
; Set frame format: 8data, 2stop bit
LDI r16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
OUT UCSRC,r16
RET
;Ïðîöåäóðà îòïðàâêè áàéòà
uart_snt: SBIS UCSRA,UDRE ; Ïðîïóñê åñëè íåò ôëàãà ãîòîâíîñòè
RJMP uart_snt ; æäåì ãîòîâíîñòè — ôëàãà UDRE
OUT UDR, R17 ; øëåì áàéò!
RET
;Èíèöèàëèçàöèÿ SPI
spi_init:
LDI R16, (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<DORD)
OUT SPCR, R16
LDI R16, (1<<SCK)|(1<<MOSI)|(1<<CS)|(1<<PB4)
OUT DDRB, R16;
SBI PORTB, CS; Óñòàíàâëèâàåì â 1
RET
;Òåïåðü ïîñûëêà ïðèâåòñòâèÿ
SENT:
LDI ZL,Low(LabelSTART)
LDI ZH,High(LabelSTART)
M1: RCALL uart_init
LD R17,Z+
RCALL uart_snt
CPI ZL,Low(LabelEND)
BRNE M1
M2: CPI ZH,High(LabelEND)
BRNE M2
RJMP STOP
STOP: NOP
RJMP STOP
С виду все жизнеспособно, а что работает не так?
В том то и дело, что не работает!
Не посылается байт в UDR.
Смысл, я так понимаю понятен. Берём байт из оперативки и посылаем в ком-порт.
В реале не работает. По ощущениям не вызывается подпрограмма uart_snt
Писал в авр-студии.
Ну прогони код трассировкой. Код то нативней некуда. И как у тебя usart_snt может не вызываться если у него ПРЯМОЙ вызов?
DI HALT спасибо за подсказку :) Я пробывал.
Короче, в студии всё работает, в протеусе работает, на железе нет :(
ааа… мозг плавится!
Ну значит у тебя косяк с инициализацией усарта. Либо тактовая частота не та. Уверен, что там 8мгц?
DI HALT, а ещё вопросик, у тебя есть учебные статьи по работе SPI???
пока нет. Да там все просто — выставил скорость да кидай байты в приемный регистр. Проще уарта даже
т.е. устанавливаем только делитель??? А ведомый сам подхватывает скорость по синхроимпульсам?
Вопрос о USART
на меге8 пытаюсь принять данные с датчика
9600Baud, 81N
9600, 8 bits, no parity, with one stop bit.
буржуйским языком написано, 9600бод, 8бит, без четности
кварц 3686400Гц
вот так конфигурирую USART,
ldi temp,0;
out UCSRA,temp;
ldi temp,0b10010000;
out UCSRB,temp;
ldi temp,0b10000000;
out UCSRC,temp;
ldi temp,0b10000110;
out UCSRC,temp;
ldi temp,23;//23
out UBRRL,temp;
принимаю по прерыванию
в инструкции к датчику сказано что должны идти символы АСКИ. «R»это 0х52 и CR это 0х0D
вместо них похоже принимается 0х06 и 0x2B
06 67 64 79 2B блоки такой структуры
считал ошибки по флагу FE, насчитывает почти при каждом прерывании
почему это может быть?
Да мало ли что там датчик передает. Проверь вначале терминалкой правильность программы.
к сожалению нет терминала
подключу передающий контроллер, проверю
подключил другой контроллер, на передачу, с такой же конфигурацией, принимает без проблем
скорость 9600бод, точно, контроллеры были с разной тактовой, правильно выбрал UBRRL
я правильно сконфигурировал USART под требования датчика, которые я указал?
если да, то что то не то с датчиком
на нем стоит контролер PIC16f676, он может конфликтовать с мегой8?
буду очень рад дельному совету, ато 2дня бьюсь
увы значения битов для UCSRA и прочих я не помню. А в справочник лезть лень, да и некогда.
Распиши свои магические числа побитам скажу так или не так.
вроде все правильно
UCSRB : 1<<RXEN, 1<<RXIE
UCSRC : 1<<URSEL, 1<<UCSZ0, 1<<UCSZ1
подал сигнал с датчика на лог-анализатор, выдает то, что заявлено
а контроллер принимает не то
А тактовая частота точно та самая? Уверенность в этом 100%?
С датчика 9600бод точно сигнал
на контроллере 3 686 400, точно, потому что я соединял его по USART с контролером который работал от внутреннего 1МГц.
UBRRL=23 для 3 686 400
UBRRL=6 для 1МГц и прием работал
Если один МК верно передает, а второй верно принимает.
А когде у нас датчик то прием не верный.
Методом исключения остается проблема в датчике. Датчик выдает что то не то.
Спасибо за помощь, оказалось, что сигнал с датчика был инвертированный.
Датчик, случайно не УЗ дальномер? ;)
Кстати, когда ты сказал что там PIC была мысль такая (они так могут), но что то подумал что такой изврат не встречается никогда.
Дальномер, Mxsonar EZ-1, сталкивался с подобной проблемой?
Ага. Именно с ним. Тоже долго мозг ебал на тему чего же он мне не то шлет. Правда я в терминале смотрел.
Написал даже разработчикам. Очень оперативно ответили. Двух часов не прошло :)
Извращенцы.
офтоп конечно, но
успешное устройство с этим датчиком получилось?
Устройство нет, пока экспериментирую. Я для робота его брал, но показания с него адски скачут и чет не особо меня это радует. Думаю как бы их фильтровать.
Добрый день. Di, а нет у тебя проверенного кода для работы с UART? На рабочем примере гораздо проще написать свое, попутно и разобраться, что там к чему. Только на ассемблере нужен, желательно для меги8.
Еще вопрос, получится у меня связать по ЮАРТ два проца через 2 max232, если один кварцованый (16 мгц), а второй от внутреннего генератора работает? А годится вообще RS232 для применения в заводских условиях?
Есть. Под какой контроллер?
Мне лучше под Mega 8, но в принципе все-равно. Мне для примера, чтобы свою написать. Единственное, если под другой МК, скажи на что обратить внимание, чем могут отличаться.
И еще. Казалось бы простой вопрос, но не найду ответа. Везде описывается связь МК с компом по RS232. Там понятно — преобразует компортовские 12в до уровня 5в. Если же два МК соединять через MAX232, то питать их тоже от 5в надо? А в линию 12в она выдаст от своего внутреннего преобразователя? Или лучше взять 2 RS485 ?
Для мега8
Обычно для всех мег одинаково. Разница может быть в именах регистров (если у меги два уарта, то у них будут номера 0 или 1) и в бите выбора целевого регистра URSEL он может быть, а может и не быть.
Если два контнроллера соединяются УАРТ’оми, то ставить MAX232 не нужно, если они конечно не очень далеко друг от друга расположены. Ели далековато, то тогда для защиты от помех думаю стоит. И то, для бОльших расстояних надо бы подумать про другие сети, типа RS485
Di, спасибо. Я имел ввиду не только это, а кусок кода, где можно разобраться, как данные вносятся в UDR, из него извлекаются. Хочу написать макрос, в который надо было бы передать несколько параметров и не думать потом больше, как там оно все происходит, т.к. далеко не у всех такая светлая голова, как у тебя — забывается. А с макросом все ясно — вот макрос, вот данные. Отправил и забыл, как там оно работает. Так же и с приемом.
А там все просто. Закинуть данные в UDR
OUTI UDR,0xFF
например. А забирать по прерываниям
Т.е. выставляешь обработчик прерывания и там делаешь
RX_OK:
cохранение регистров
IN R17,UDR
восстановление регистров
RETI
Спасибо еще раз. Буду разбираться.
Что-то не увидел или нет на этой странице. А ноги-то как-то надо конфигурировать, или при инициализации UART это аппаратно происходит? RXD — вход, TXD — выход?
Он сам.
Прошу пощения, что не по теме — навеяло. Жаль, что на этой странице никаких меток для себя нельзя поставить. Найдешь нужное место, потом туда-сюда — заново искать надо. А страница большая — не так и просто. Да и в АВР Студии добавили бы еще один «верхний прозрачный слой», что бы можно было над текстом прорисовать стрелками переходы. Было бы намного удобнее. Что там эти буржуи до таких простых вещей не додумаются, что ли?
rjmp USART_Receive_Complete ;URXC ;addr=$00b
rjmp USART_Data_Register_Empty ;UDRE ;addr=$00c
rjmp USART_Transmit_Complete ;UTXC ;addr=$00d
; Инициализация UART
.dseg
.equ XTAL = MainClock
.equ baudrate = 9600
.equ bauddivider = XTAL/(16*baudrate)-1
.cseg
OUTI UBRRL,low(bauddivider)
OUTI UBRRH,high(bauddivider)
OUTI UCSRA, 0
OUTI UCSRB,(1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)
OUTI UCSRC,(1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
;_________________________________________________________
sei
;==========================================
Start:
LDI R16,’E’ ; загоняем в регистр код буквы «E»
RCALL uart_snt
rjmp Start
; бла бла бла куча какого нибудь другого кода.
; Процедура отправки байта
uart_snt: sbis UCSRA,UDRE ; Пропуск если нет флага готовности
rjmp uart_snt ; ждем готовности — флага UDRE
out UDR, R16 ; шлем байт!
ret
Хе-хе.) Всю ночь разбирался, так и не понял, почему при готовности UDRE не происходит
перехода на USART_Data_Register_Empty (прерывание) ? Да и отправка байта при частоте 8Мгц занимает 1 млсек в А-студии. Это нормально для 9600 бод? Пытался RXD сбросить в ноль (симитировать приход байта) — тоже никакого прерывания не произошло. Что за фигня такая?
Если я правильно понял, то механизм работы ЮАРта примерно такой — в основной программе постоянно проверяем готовность UDRE, как только он готов — загружаем в него байт и продолжаем в основной программе крутиться, ждать готовности UDRE?
А если отправлять нечего, ( готовый UDRE вызывает прерывание), то что же, он постоянно будет прыгать на обработчик?
Ну так ты бы еще разрешил прерывание от UDRE то :) тогда бы и заработало.
9600 бод это 9600 битов в секунду. Один байт — 10бит Так что как раз 1мс и получается примерно.
http://easyelectronics.ru/avr-uchebnyj-kurs-rabota-na-preryvaniyax.html
вот как надо работть с USART на прерываниях.
А будет ли мешать прием и передача данных по UART, генерированию двух ШИМ-ов? Планировалось завести мышь подключенную к АВР и еще принимать сигнал по Инфракрасному порту. Все больше и больше кажеться, что я буду терять кучу данных. И по большей части из за шим, хоть он и занимает очень мало времени…
А какая связь между ШИМом и Уартом??? Если правильно все организовать (на прерываниях, все аппаратно) то затыков быть не должно.
Я имею ввиду тот эффект который получился в конце статьи про шим. =-) Хотелось уяснить, есть ли вероятность того, что шим не повлияет на целостность получаемых данных
Уарт принимает данные аппаратно, по прерыванию они только забираются из буффера. Т.е. у тебя прерывание должно быть доступно как минимум раз в байт, на текущей скорости уарта.
Помогите пожалуйста! немогу понять почему не работает программа для Atmega16. Суть программы-скорость 4800 бит/с (для кварца 14,318 МГц ),при получении последовательности символов «start» начать непрерывные посылки в порт символа «9″.
вот текст моей программы:
.include «m16def.inc»
main:
ldi r16, 116 ;при 1 в U2X 14318000/(8*(UBRR + 1))=4798
out UBRRL, r16 ;при UBRR = 372
ldi r16, 1 ;372 = 256 + 116 = 100000000 + 01110100
out UBRRH, r16 ;116= 64+32+16+4
ldi r20, (1<<RXEN)|(1<<TXEN)
out UCSRB, r20
ldi r20, (1<<U2X)
out UCSRA, r20
priem:
sbis UCSRA, RXC
rjmp priem
in r16, UDR
cpi r16, 115
brne priem
sbis UCSRA, RXC
rjmp priem
in r16, UDR
cpi r16, 116
brne priem
sbis UCSRA, RXC
rjmp priem
in r16, UDR
cpi r16, 97
brne priem
sbis UCSRA, RXC
rjmp priem
in r16, UDR
cpi r16, 114
brne priem
sbis UCSRA, RXC
rjmp priem
in r16, UDR
cpi r16, 116
brne priem
SendByte:
sbis UCSRA, UDRE
rjmp SendByte
ldi r16, 9
out UDR, r16
rjmp SendByte
Если слово «start» заменить на букву «s» и переписать с учетом этого программу ,то все работает. Программа писалась в AVR studio, прием и передача осуцествлялись с помощь. программы Hyper Terminal
Ну а сам то не догадываешься? Прогони в отладке авр студии и поподставляй на проверках в R16 твое значение. Сам поймешь что дальше первого сравнения у тебя программа не полезет никогда.
Кажется понял,у меня в программе ,не дожидаясь посылки следующего за первым слова, программа переходила на метку priem. я это исправил,сделав у каждой буквы свою метку:
priem:
sbis UCSRA, RXC
rjmp priem
in r16, UDR
cpi r16, 115
brne priem
priem2:
sbis UCSRA, RXC
rjmp priem2
in r16, UDR
cpi r16, 116
brne priem2
и так далее. спасибо за помощь! проведу испытания на железе
>>Самый прикол тут — это бит селектора URSEL дело в том, что по неизвестной причине
>>создаетели решили сэкономить байт адреса и разместили регистры UCSRC и UBRRH в
>>одной адресном пространстве.
Я думаю причина понятна. Заняты все 0x3F регистров и чтобы не вылезать за область работы out, они решили объединить самые ненужные, по их мнению, регистры :)
Добавлю свои 2 копейки.
мега8, 4 мгц внутренний генератор. инициализирую как тут в примере, 9600,8-нет-1.
передаю … в терминале — мусор. экспериментирую, ставлю 7бит — О! работает!
Во, думаю, обманули, 7 бит а не 8 получается. Смотрю в даташит, в студии на битики — да нет, все как надо. Экспериментирую со скоростью (в терминале) — соответственно посылка уменьшается или увеличивается, но мусор. С передачей примерно та же фигня, но иногда срабатывает на 8 бит, иногда на 7 иногда вообще никак. Думаю, точно со скоростью косяк — пересчитал формулу — не обманывает Ди, фузы-точно на 4 мгц, благо когда шьешь через дракона и студию, ошибиться сложно. И тут я припоминаю что генератор-то калиброваный, и но вроде как вручную. Читаю даташит — точно, автоматом загружается значение калибрации для 1 Мгц (Вот уроды, не могли сразу нужное значение загружать?) Считал значение для 4 Мгц, воткнул в начало проги
ldi r16, 0xa7 ;Это значение считано из МК
out osccal,r16
И все! глюки исчзли! 8-нет-1! и прием, и передача.
Так что, уважаемый читатель, если последняя надежда настроить УАРТ умерла, все настройки перепробованы, уже 3 часа ночи, и т.д. — попробуй откалибровать кристалл!
Обана и на 9600 изза калибрации такие гоны???? Фигасе, никогда не сталкивался. Не настолько там сильно влияет калибрация. Это больше для доп точности.
Насколько я понял из даташита, особенно графика зависимости частоты от OSCCAL (Page 276, Figure 172. Calibrated 8 MHz RC Oscillator Frequency vs. Osccal Value), этим регистром можно менять частоту от 50% до почти 200% (4,5…15 Мгц). Вот он, оверклокерский рай!
Здраствуйте. Есть у меня одна проблемка: ратотаю с 64й мегой, суть программы в том что она после инициализации ждет приема символоа с компа, отправляет ему ответ, молв «все ОК» и переходит к дальнейшему выполнению своей работы. Проблема в том что после каждого приема прога уходит на прерывание, записывает в буфер и выходит из него в … RESET! Притом косяк этот только на 64й появился, рядом валяется 16я мега на которой этот код вдоль и поперек обкатан, а тут на 64ю перевел и пошло-поехало. Что это может быть?? Может ли это быть косяк платы или всеже прога?
(Если надо выложу код)
Возможные косяки:
1) криво инициалзировал стек.
2) Кривая таблица векторов прерываний.
Код на асме? Если на асме, то на мегу 64 его так просто копипастой не перебросишь, надо ряд адресов подправить. В частности таблицу векторов.
На асме.
Вот табличка, писал с даташита:
http://easyelectronics.ru/repository.php?act=view&id=14
Кстате в АврСтудио гонял все работает на ура.
И инициализация стека вот:
; PROGRAMM INIT ===========================================
Reset: OUTI UDR0,’0′
OUTI SPL,low(RAMEND)
OUTI SPH,High(RAMEND)
.include «init_uart.asm» ; Инициализируем UART
SEI ; Разрешаем прерывания
; MAIN PROGRAMM +++++++++++++++++++++++++++++++++++++++++++
Кстати, вот только сейчас аццкий глюк нарисовался %) У меня после запуска и инициализации всех портов, уартов и прочего загорается контрольный светодиод, так вот он теперь вообще то сразу загорается то через секунд 10, то вообще не загорается. Это что еще может быть?
Да что угодно, вплоть до срыва стека из-за косяка в программе.
Надо понять где глюк в железе или в софте. Софт исключить проще всего. Пишешь программу в которой точно понятно, что контроллер ребутнулся, а потом делаешь экшены которые гарантированно работают и как бы орудуют периферией. Например щелкают релюшками просто так.
Прогоняешь в отладчике, чтобы убедиться что не глючит и проглядываешь включив мозг, чтобы точно убедиться что глючить там нечего (прога должна быть тупой и простой) и если оно ребутится, то косяк в железе.
Я уже так сделал, понавесил светодиодов на все порты и написал тупую щелкалку. Нашел косяк с пином PD0 при инициализации которого контроллеру взрывало мозг, и точно установил что срыв на Reset идет после выхода их обработчика прерывания по приему. Тока непойму никак что может провацировать срыв на выходе из обработчика?
Кстати не в нем ли проблема :
RX_OK:
PUSH R16
IN R16,SREG
PUSH R16
IN uBUF,UDR0
POP R16
OUT SREG,R16
POP R16
RETI
uBUF это R16? Если нет, то его тоже надо в стек прятать. Или он нигде не используется кроме как буфер для данных из уарта?
А нет ли у тебя замыкания между PD0 и RESET? А то может инитишь PD0 на что нибудь, а у тебя ресет происходит. Собака включена?
Покажи весь код, особенно обработчики прерываний (кинь в репозиторий). Гляну.
Собаку не включал.
uBUF это регистр чисто для вытаскивания из уарта, большой буфер просто не нужен.
PD0 идет рядом с XTAL1. Но я уже забил его инитить а глюк всеравно остался.
Вот код для теста накидал (с «мигалкой») на которой у меня этот глюк очень четко проявляется.
В процессе работы он присылает ы терминал «+» после инициализации и потом ы цикле шлет вот такую ерунду «0о0о0о0о». Как- только отсылаю какой нибуть символ снова вылазит «+».
Вот
http://easyelectronics.ru/repository.php?act=view&id=15
Вот лажовый кусок:
Ты сохраняешь срег, а потом восстанавливаешь его. И зачем? Для того, чтобы макросом
CLRB UCSR0A,7,R16 зафачить регистр R16 и еще флаги (а в макросе этом, емнип, они не могут не юзаться, т.к. сьем бита идет через логические операции.
Доставание данных из стека должно быть когда все уже сделано, перед самым выходом.
Но одно непонятно — какого хера оно в ресет уходит. Ну зафачит цикл, но не ресет же. Где то мы прозевали какую то хуйню. Дай ка мне на мыло проект целиком. dihalt@dihalt.ru интересно где же лажа :)
Погонял я тут вот такой код обработчика:
RX_OK:
OUTUR R16
PUSH R16
IN R16,SREG
PUSH R16
IN uBUF,UDR0
POP R16
OUT SREG,R16
POP R16
OUTUR R16
RETI
Так вот на входе, перед сохранением в стек, R16 какоето число а на выходе всегда 255!!! и после этого прога уходит в RESET. Я понимаю что это срыв стека, но не понимаю изз-а чего ему быть в этом месте, именно в обработчике.
*Макросом OUTUR R16 я отправлял в терминалку, глюк есть что с ним что без него.
Это не срыв стека, это неправильный выход из прерывания. Ты не слишком рано достал данные из стека =) правда на выход это влиять не должно.
Отправил проект на мыло. Но вот копчиком чувствую что лажа гдето в стеке закралась, разве что-то еще может такие глюки плодить. Что интересно симулятор прогу прокручивает и никакой лажи и в ппомине не видно. Скоро в стену бится начну%)
Знаешь в чем еще может быть лажа — совместимость с ATmega103. Там есть fuse бит и изначально он стоит в режиме 0, т.е. включен режим совместимости с ATmega103 а там другая адресация, нет мемори мапед регистров. В результате получается странная херня — в симуляторе работает, т.к. студия думает, что мы сидим на меге64, а в железе глючит, т.к. фактически мы работаем на 103 меге :)
А это идея, надо поковырять. Я тут еще нарыл инфу о том что RamEnd для ATmega64 = 0x10FF, а это явно больше чем 0xFF.
Стек я инициализирую как в 16й,
OUTI SPL,low(RAMEND)
OUTI SPH,High(RAMEND)
может тут по другому надо, блин, смущает меня меня это 0x10FF…
Да ерунда это. Какой бы ты рамэнд не взял, оно нормально войдет. т.к. по любому меньше чем FFFF и все ок. Т.е. двубайтное. Не могу понять почему у тебя стек срывает и вообще от чего ребут идет. Даже если и работает на меге103 (щас в симуляторе запустил на 103), то от этого может периферия отпасть, память меньше чем в 64, но на возвраты из стека никакой разницы!!!
Я те в мыло тоже кой чего скинул. Позырь, там ты POP забыл в обработчике.
И еще, у тебя срывает только в железе? А в симуляции все ок? Т.к. у меня в симе все шикарно.
ВЫкини нахер все макросы. Оставь нативный ручной вывод, А то там у тебя столько прогрузов стека ,может забыл чего. И выброси все кроме закидывания оО в уарт (причем вручную, а не макросом). Задержку можешь оставить. Ну и обработчик прерывания естественно. Если и ЭТО будет глючить, то ищи утечку по плате.
Бля, говорят же работает — не трогай. Не открыл бы дизассемблер не понял бы.
Понял в чем жопа? ;)
Не, башка уже не варит. В чем?
На макрос посмотри и на то ЧТО он делает!
Ты грузишь данные через него в Stack Pointer. Но как? ПРедварительно сохранив R16 в стек! Но стек то еще не инициализирован. В результате со указателем стека получается интересная метамарфоза :) Ты как бы его грузишь и одновременно двигаешь туда сюда командами PUSH/POP причем побайтно. В результатет чудом получился интересный замут — значенение не 10FF, а 1100 :) Разница всего в один байт!
Вроде бы в конце памяти, но на байт дальше. Итог — данные проваливаются в никуда. Но ты этого пока не замечаешь, т.к. ничего критичного там нет.
Но почему все работает в студии? А потому, что у тебя там до жопы макросов и во всех из них юзается дофига PUSH и POP и когда ты вручную вызывал прерывание, то в всегда это было тогда, когда выполнился хотя бы один PUSH и указатель стека вылезал в адекватную область. Но стоит выполниться прерыванию в том месте, где PUSH не прошел — как все рушится, т.к. адрес сохраняется в несуществующую область памяти. Возникает вероятностный глюк.
Но это теория и второй скрытый баг, у тебя же все вылетало нахер изза другого.
Бит совместимости с ATmega103. Он по дефолту включен и ты работаешь не с мегой64, а с мегой 103, а у ней оперативка короче на 96 байт. Таким образом, указав рамэнд от меги64 ты указал не просто на байт дальше, а на целых 96 байт дальше. В результате у тебя стек не просто плавает на границе адекватных адресов, а оказалс вообще за границей памяти. В макросах ты этого бы и не заметил — там пофигу. Но вот на первом же адресе возврата у тебя наступает армагеддон :)
Блин, заработало-же))))
Убрал я эту соместимость нахер и инициализировал стек вручную через LDI n OUT, и все встало на свои места, никаких долбаных ребутов.
СПАСИБО ОГРОМНОЕ!!! А то я б тут всю ночь сидел, а в понедельник железяку уже отдавать нада)
С тебя пиво ;)
Подправь как проект под мегу103 ;) да запусти.
Не, не помагло((
Я вот такую байду в код загнал тупа посреди цикла:
LDI R16,’E’
OUTUR R16 ;отправка
PUSH R16
POP R16
OUTUR R16 ;отправка
И получаю на терминал что сначало по терминалке приходит буква «Е», потом она лезит в стек, потом вылазит оттуда и приходит уже «!» Я фигею…
У меня по USART не передается ноль…
АЦП в старшем разряде содержит ноль, передаю два байта, младший проходит, старший нет.
Как передать 0?
Записать в UDR ноль
…
; забираю данные с АЦП
IN R16,ADCL
IN R17,ADCH
; пишу в УАРТ младший байт (в R16)
RCALL UART_SNT
MOV R16,R17
; пишу в УАРТ старший байт (был в R17)
RCALL UART_SNT
…
если в старшем байте после преобразования оказывается 0, то терминал на другом конце линии УАРТ принимает только 1 число, если же не 0, то отображаются 2 числа.
Ну так что ты хочешь. В Ascii код 00 имеет служебный символ, который не отображается в терминале. Используй терминалку которая может в хексах представлять вывод.
Я тут новенький, поэтому, во-первых хочу сказать огромное спасибо за этот сайт, действительно, здесь можно научиться программировать МК с нуля (как это происходит у меня:), а во вторых — такой вопрос к уважаемому DI HALT:
учусь работать с UART на основе этой статьи, застрял на работе с ним через буфер
http://easyelectronics.ru/repository.php?act=view&id=17
соответственно при запуске в терминал сыпятся «Hello Interrupt Request!!! «, если при этом ввести что-нибудь в терминале и приостановить выполнение (Ctrl+F5) — в RAM будут введённые данные, как им и положено, но если вознобновить выполнение (F5) и снова приостановить — в RAM на месте прежде введённых байтов — нули, непонятно, почему перезаписывается нулями буфер ввода???
P.S. кстати, стирается не только то что было помещено в буфер, если просто забить в произвольно месте байты в RAM а потом запустить и приостановить программу — на месте данных — нули, сохраняется только SP и первые 2 байта указателя на строку o_O сломал себе мозг….
Каким образом данные в терминал вводились? В студии же нет терминала? или юзался хапсим? Протеус? Распиши подробней что делал.
Пишу подробнее:)
терминал юзаю wTerm, железо реальное;) отладка через jtag (программатор какой-то olimex)….
пока сидел разбирался, начало кое-что проясняться:) если посмотришь код, есть у меня обработчик прерывания, почти полностью скопированный с тебя:) ставлю я брякпойнт на RETI из этого прерывания и смотрю на SP, почти всегда у него значение на выходе 10FD, но иногда по непонятным мне пока причинам там оказывается 1100, ну и соответственно у меня прога начинается с org 0000:) всё остальное — следствие — т.е. чистится по-новой память, инициализируется уарт и т.д. почему срывается стек понять не могу, ведь выполняется одна и та же процедура обработки o_O
Прошу прощения за сумбурное изложение, просто совсем уже убился я об этот стек….
Чето сайт атмела лежит. Не могу шит на 90кан128 качнуть. Позырь фузы, там нет никаких гадских режимов совместимости с чем нибудь. А то у меги128 есть, например, бит совместимости с мегой103 (то же самое почти, но памяти меньше) и по дефолту, что самая жопа, этот фуз включен. И получается что стек пробивает, т.к. в реале он адресуется не туда.
Вот в этом же посте, буквально десятком комментов выше, мы с BenG’ом этот глюк ловили. Тоже стек срывало непойми с чего.
Тфу, разобрался в своём косяке… В начале программы не заткнул все неиспользуемые прерывания, вот оно и глючило прыгая неизвестно куда:)
Всем привет!
Пробую работать с UART на ATtiny2313. Простой пример — вывод строки.
Выдает белиберду — в некоторых битах неточности.
Попробовал поменять делитель bauddivider — вместо стандартного 51 для 8Мгц и 9600 — пробовал немного сместить. На числе 55 — стало выдавать нормально.
Схема БЕЗ кварца, работает на внутреннем генераторе 8МГц.
Работало пару дней, теперь перестало. Опять белиберда. Подбирать коэффициенты уже устал.
Это так действительно должно быть, что без кварца не получится?
Или можно как-то оптимизировать — снизить частоту процессора, снизить скорость передачи?
Кварц некуда впихивать, все ноги заняты.
А ты частоту точно высчитал? FUSE Бит CKDIV8 выключил?
Без кварца нормально робит вплоть до 115200 И не надо ничего подбирать.
Выключил, я специально начал с программки мигания светодиодом раз в секунду.
Только что замерил — а светик-то мигает не раз в секунду… а 10 раз за 16 секунд!
но изменил, теперь мигает как надо… а вот в терминал по прежнему корявые байты приходят…
Либо у тебя в проге косяк и поэтому оно постоянно ребутится и переинициализирует периферию. Либо кварц запустился на левой гармонике (что вряд ли, это редкость).
Косяк был в «равенстве» регистров UBRRH и UCSRC. Хотя в даташите НИЧЕГО по этому поводу не написано, и бит UCSEL в даташите на ATtiny2313 отсутствует.
При инициализации порта и настройки 8N1 в регистре UCSRC одновременно записывался и UBRRH, и настройка скорости сбивалась.
Но все равно, доводка напильником осталась — при Bauddivide=54 работает лучше чем на стандартной 51.
Адреса у них разные:
.equ UCSRC = 0×03
.equ UBRRH = 0×02
Да и я очень много работал с тини2313 и никогда не имел проблем с тем, что что то не туда записывалось.
Адреса у них разные, да. Но реально, даже при симуляции в AVR Studio при записи в UCSRS любого бита, либо целиком — все так же копируется в UBRRH. Был бы чип «левый» — еще можно понять, но ведь и Студио ТАК показывает!
Нука пришли ка мне весь проект на мыло dihalt@dihalt.ru погляжу что там да как.
действительно в AVR Studio при записи в UCSRS изменяется UBRRH,
если порядок поменять выглядит вроде нормально. Это ошибка AVR Studio или в чипе тоже?
действительно в AVR Studio при записи в UCSRS изменяется UBRRH,
если порядок поменять выглядит вроде нормально. Это ошибка AVR Studio или в чипе тоже? Чип ставил mega48.
Надо проверять. ВОзможно гон студии. ТАм было что то подобное. В мега48 точно нет бита выбора регистра?
я сделал первый способ на атмеге32
Main: RCALL uart_rcv ; Ждем байта
INC R16 ; Делаем с ним что-то
RCALL uart_snt ; Отправляем обратно.
JMP Main
но обратно в терминал возвращается значение большее не на 1 а на 129 (0х81)
использую переходник на ft232rl , он работает нормально я это проверял соединяя рхд с тхд и получаю тоже значение в окне терминала что отсылал.
Возможно скорости просто не совпадают. Попробуй закоментировать INC и должно возвращать то же самое, но этого не будет :) Разберись с тем на какой частоте работает МК, на какую частоту настроен UART и терминал.
Причем с самим протоколом можно не заморачиваться — все реализовано аппаратно. Разве что захочется завести второй UART, тогда придется делать его программно.
А что будет, если на одной стороне выставить одну скорость, а на другой — другую. Эти устройства смогут договориться?
Не смогут. Скорости должны совпадать.
Тогда еще один глупый вопрос. Помню давно когда пользовался модемом, в настройках COM порта менял baudrate и это ни на что не влияло. Как модем подстроился под изменившийся baudrate? Меня этот вопрос давно мучал =)
Да, и кроме скорости включал/отключал бит четности, старт/стоп. Тоже все работало после этого.
О всех этих параметрах договариваются на берегу, до начала передачи
Можешь пояснить, что это значит? Договариваются по UART или по другим каналам? Или договариваются условно? =)
Договариваются условно. Т.е. заранее определяемся на какой частоте будем общаться. И эту частоту выставляем с обоих сторон.
Ну есть алгоритмы высчитывания бодрейта. Особенно если знаешь что тебе пришлют. Те же ARM контроллеры имеют уарт с определением бодрейта. ТАк что алгоритмы то есть. С другой стороны зачем грузить зря процессор ненужными вычислениями если можно сразу выставить правильно.
А биты четности, стоп биты он тоже может определить?
Наверное. Главное поймать несколько байт и их проанализировать. Модему проще, т.к. ему в основном идет первая команада вида АТ… и уже зная, что первый байт «А» можно вычислить,что у нас за частота, сколько стартов, стопов, какая четность и тыды.
подскажите пожалуйста, целый день убил сегодня.
код ниже, по идее при оправке по USARTу через терминал(терминал v1.9b) должен возвращаться символ обратно а что бы не оправлял возвращается вот такая ботва
гыде туплю))), Спасибо
.include «tn2313def.inc»
.MACRO outi
LDI R20,@1
OUT @0,R20
.ENDMACRO
.org 0
start: rjmp reset
.org 7
rjmp prin
reset:
sbi ddrd, 5 ;мигает
outi tccr0a, 1<<com0b0 ;
outi tccr0b, 1<<cs00|1<<cs02 ; диод
outi ubrrl, 207 ;2400
outi ucsrb, 1<<rxen|1<<txen|1<<rxcie ; разр. прием передачу, прерывание-прием завершен
sei
cicle:
rjmp cicle
prin:
outi tccr0b, 1<<foc0b ; вкл. выкл. диод
in r16, udr
inc r16
nop
out udr, r16
reti
стоп биты, проверка на четность скорость выставлены
У тебя стек не инициализирован. А значит при выходе из прерывания происходит его срыв и твоя программа идет на йух.
добавил ,картина не изменилась, схема собрана на макетке мож наводки там или еще что, потому что прога работает в принципе как положено при каждой отправке символа диод меняет свое состояние, а вот символ отправленный не возвращается.
А кодировку в терминалке ни как менять не надо? я отсылаю просто еденичку «1″
она вроде как и должна вернуться???
http://easyelectronics.ru/repository.php?act=view&id=39
Вот позырь, гарантированно работающий проект. Найди разницу как грицо.
А как ты шлешь единичку? Как 1 или как ’1′ ? потому что 1 это просто 1 и в терминалке ты ее не увидишь (не отображаемый символ), а ’1′ это код цифры 1, т.е. 0х31
спасибо большое
Вопрос 1.
В многопроцессорном режиме USART (один мастер и несколько подчиненных),
при передаче от подчиненного к мастеру, должны ли быть отключены передатчики остальных ведомых? Т.е. не нарушится ли корректность режима шины?
Вопрос 2.
В том же режиме. Насколько велика нагрузочная способность передатчика (мастера), если у нас 20-30 ведомых? Может какой-то буфер надо городить?
Тишинааа…
Неужели никто не знает?
DI HALT я совсем недавно бросал на Радиокоте в личку вопрос по этой статье. Может есть что прокоментировать. Просто почту не нашел поэтому написал туда.
Какой вопрос то?
Дойдя до ручки, и устав биться головой об стену я решил все-таки написать. Особенно после того как прочитал главу учебного курса « Передача данных через UART».
Я пытаюсь реализовать девайс на 2313 подключенный к ПК и выполняющие «простые движения». Таймер 0, каждую секунду пихает в порт запрос АА. На компьютере работает сервис который приняв АА понимает что устройство подключено отправляет А1, на что девайс должен вернуть состояние пина 2 порта D. Если 1 то отправляем АВ если 0 то АС. После этого компьютер посылает А2 и девайс должен вернуть 4 байта температуры. Все это время таймер отключен. После того как все выплюнуто в порт, таймер включается и через секунду снова посылает байт присутствия АА. Все просто и понятно когда проходит один прогон. А вот на втором заходе хрень получается. Я залогировал данные в файле log.txt.
Одним словом после первого измерения идет 3 запроса 3 ответа на измерение пина и 3 запроса на температуру. Причем пачкой. Как будто где-то что-то стояло в очереди и вышло наружу. И тут же в порт пошло 2 температуры сразу. Дальше больше.
Прочитал в ДШ что нужно с осторожностью использовать команды sbic sbis. Вроде они влияют на буфер FIFO. А где этот буфер я так и не понял, тем более как они на него влияют. Может быть здесь собака порылась? А как мне без этих команд считать состояние нужной ноги… нужны они мне.
Хотя, ДАЖЕ, или скорее всего я напортачил с УАРТ. Я использую только одно прерывание USART_RXC. Получаю А1 или А2 проверяю и выпадаю из него. Таймер тоже на прерывании. Считает секунду – останавливается, посылает АА, измеряет температуру и снова запускается.
Что можете посоветовать в моем случае? Использовать прерывание на передачу? Задать буфер? Я уже совсем заплутал.
При чем тут UART вообще? У тебя один байт уходит нормально? Если да, то косяк в кривом алгоритме. Буфера у уарта нет, точнее есть, но он всего на один байт так что за раз можно отправить максимум два байта. Если делать это быстрей чем уарт может прожевать, то будет лажа.
sbic/sbis это команды ветвления. Ни на что кроме порядка выполнения кода они не влияют. И уж тем более не влияют на периферию.
Скорей всего у тебя криво организована программа и где то либо срыв стека, либо просто логика идет не так как ты задумал.
не пойму как файло прикрепить
http://easyelectronics.ru/repository.php?act=view&id=41
блин да вроде логика проста, может и правда стек… надо глянуть сколько в 2313 стек
Сразу вижу два глобальных косяка — у тебя в прерываниях регистры не сохраняются в стеке и не достаются оттуда при выходе. Причем поганятся не только флаги, но и temp через которое у тебя все сделано. Естественно логика рушится мгновенно.
с темпом я понял, а еще какие регистры нужно сохранять CSEG?
Все что используются в обработчиках прерываний. Ну и SREG само собой.
ок. буду пробовать
здравствуйте уважаемые пользователи сайта, прошу помощи…написал программу в CVAVR, контроллер атмега 8535,частота 8Мгц не получается с UARTом. По прерыванию от UART, в зависимости от посланного символа, загорается светодиод…все хорошо работает, но когда через UART обратно посылает какое либо сообщение светодиоды гаснут((настройки все верны и перепроверенны раз на 50…в чем может быть причина??проверяю работоспособность в Proteuse сигналы нормально принимаются.
interrupt [USART_RXC] void usart_rx_isr(void)
{
u=UDR;
if(u==’1′)PORTD.2=1;
if(u==’2′)PORTD.3=1;
if(u==’3′) putchar(‘y’);
}
обработчик прерывания..пробывал через switch, тоже самое…отправлял через printf тот же результат…надеюсь кто нибуть поможет. Заранее спасибо.
А в основной программе что? Ну и проверь в железе, а то протеус такой протеус. Правда с уартом там глюков я не видел, но вот TWI в протеусе работает неправильно
в основной программе просто горит 7разрядный индикатор…а что именно на счет железа может быть??
попробывал этуже программу в AVR Studio тажа ситуация…грешил на регистры и стек..почитал в описании программы CVAVR что при прерывании все регистры и стек сохраняются автоматически и потом обратно загружаются…может проблема в том что в прерывании по приему происходит выдача символа…пробывал разные функциии и способы выдачи сообщения ничего…есть ли книга по AVR Studio? если есть такая скажите ссылку)
Попробуй вместо PutChar применить прямой вывод в UDR
т.е. UDR=’Y';
попробовал разные способы выдачи символа по уарт….не получается….может быть причина в том что я в прерывании по приему пытаюсь выдать что то..
В прерывании можно слать. Я часто так делаю. Тут косяк где то в другом месте.
есть ли у тебя DI HALT почта? Если есть напиши пожалуйста, я тебе скину всю программу, чтобы было легче понять ошибку и разобраться в ней
dihalt@dihalt.ru кинь позырь бегло. Но сразу предупреждаю, если там будут магические числа, то даже разбираться не буду :)
нашел вроде бы причину в моей проблеме….у меня почему по выдаче сообщения обратно по UART стек обнуляется и снова происходит инициализация МК, заново происходит настройка портов и т.д,..думаю причина в этом…не знаешь причина сброса стека???
У тебя просто сброс контроллера. Причин может быть много. Например вачдог таймер. Если ты его включил. Или кривой вектор в прерывании (если не подключил библиотеку прерываний, но это в winavr не знаю как насчет свавр) еще может быть аппаратная проблема. Например кз или утечка между ТХ и ресетом (у меня один раз так было). Байт выскочил и сам себя сбросил.
тебе лучше программу в каком виде прислать в си или асемблере??и еще у меня почему регистр SREG и GIFR с ума сходят….GIFR устанавливает в 1 все биты а в регистре SREG все биты меняют свое значение..с вектором прерываний вроде бы нормально…заранее спасибо.
Пришли проект для студии с которым работаешь. Прям весь, целиком.
Столкнулся с такой проблемой. Беру данные с АЦП и засылаю в UDR, при этом фотодиодами контролирую бит от АЦП. В терминальной программе смотрю на график, а график как энцефалограмма при приступе эпилепсии. Видно что график реагирует на вращение резистором, но вот как четкости добиться не могу вкурить. Код до безобразия простой:
wait_ADC:
sbis ADCSRA, ADIF ; Пропустить если флаг конца преобразования АЦП выставлен
rjmp wait_ADC
in data, ADCH ; читаем регистр от АЦП
out PORTB, data ; закидываем в порт значение из data для подачи на светодиоды
rcall UART_sent
sbi ADCSRA, ADSC ;запускаем опять АЦП
rjmp wait_ADC
UART_sent: ;процедура отправки UARTа
sbis UCSRA, UDRE ;если не занят то послать data
rjmp UART_sent
out UDR, data
ret
Так график выглядит когда скорость с которой данные передаются не совпадает с теми на которой их терминалка ждет. Разберись с битрейтом.
Ага, разобрался — поставил скорость в два разабольше в терминальной проге…и я понял что кварц 4Мгц, который я воткнул с умным видом — не работает, так как по умолчанию на PinBoard МК работает от внутреннего генератора, походу 8Мгц, где то в доке я встречал… А вообще что лучше — внешний или внутренний кварц, при условии что задача простая и особой точности не надо? И есть ли разница по потреблению или ей можно пренебреч?
Спасибо!
Кварц ставят ради точности или скорости. Без него работает замечательно, а еще меньше боится влажности всякой. Но внутренний RC хорошо так плавает от температуры.
DI HALT такой вопрос, в описании работы UART приведен такой код
«Например, надо нам отрыгнуть текстовую строку из флеша:»
Main: NOP ; Любой произвольный код главной программы
NOP
NOP
LDI R17,low(2*String) ; Берем младший байт
LDI R18,High(2*String) ; Берем старший байт
STS StrPtr,R17 ; Сохраняем Младший байт
STS StrPtr+1,R18 ; Сохраняем Сташрий байт
UD_OK: PUSHF ; Макрос, сохраняющий SREG и R16
PUSH ZL ; Сохраняем в стеке Z
PUSH ZH
LDS ZL,StrPtr ; Грузим указатели в индексные регистры
LDS ZH,StrPtr+1
LPM R16,Z+ ; Хватаем байт из флеша. Из нашей строки
CPI R16,0 ; Если он не ноль, значит читаем дальше
BREQ STOP_RX ; Иначе останавливаем передачу
OUT UDR,R16 ; Выдача данных в усарт.
STS StrPtr,ZL ; Сохраняем указатель
STS StrPtr+1,ZH ; обратно, в память
Exit_RX: POP ZH ; Все достаем из стека, выходим.
POP ZL
POPF
RETI
STOP_RX: LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE)
OUT UCSRB, R16
RJMP Exit_RX
Вопрос: если сама строка находиться во флеше то зачем обращаться к стеку и заводить дополнительно указатель который сидит в стеке если можно отправить строку и ниже приведенным кодом?
Main:
.
.
.
.
LDI ZL,LOW(2*String)
LDI ZH,HIGH(2*String)
CLR R1
UD_OK:
LPM R0,Z+
CP R0,R1
BREQ STOP_RX
OUT UDR,R0
RETI
STOP_RX: LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE)
OUT UCSRB, R16
RJMP Exit_RX
Нет там никаких указателей в стеке. У меня код точно такой же как у тебя, за исключением того, что я сохраняю в стеке регистры, чтобы его можно было пихать куда угодно не задумываясь о том, что у нас содержимое каких либо регистров запортачится, как одну команду процессора.
Я так понимаю что смысл складирования в стек полученных битов в том, что если обработка полученных данных занимает какоето время, мы не пропустим вновь пришедший байт. Но если скажем нам на УАРТ летят 100 байт информации а у нас в данном случае буффер 10 байт, и мы не знаем что обьем информации которая прилетит сильно превышает обьем буффера, то есть после переполнения буффера нам надо обработать данные, что бы получить новые 10 байт данных, но ведь если этой обработкой этих 10 байт займется какаято функция (B) то функция (А) которая срабатывает на событие (UDR-пуст) не будет паралельно принимать и записывать в стек новые 10 байт ?
Да здесь в примере стек используется для временного хранения содержимого регистровой пары Z на время работы процедуры. В стек приходящие байты лучше вообще не складывать. А выделить изначально в оперативке достаточное место и туда складировать. И при этом заранее знать, какая порция данных будет приходить, чтобы выделить нужный объём. Если будут приходить 100 байт — значит резервировать 100. К тому же в зависимости от скорости UART’а можно успевать обрабатывать данные. Например на скорости 9600 один байт идет за 1 мс где-то.
А где ты увидел складирование в стек полученных битов? Нет тут такого.
В данном случае я имел ввиду раздел «Буферизация»
там где в регистр X записывается адрес 10 битного массива OUT_buff
LDI XL,low(IN_buff)
LDI XH,high(IN_buff)
а потом смещением адреса записываем побитно данные в этот массив. А выше приведенный код я привел для того что бы понять почему нельзя воспользоваться только (LPM R0, Z+) чтобы выстрелить строку.
Ничего не мешает взять и выстрелить строку из флеша — это быстро. Всю обработку делаешь в прерывании. Т.е. прям в обработчике берешь и хаваешь из флеша через указатель. Только указатель на текущий символ надо хранить в памяти. И при входе в прерывание загружать его из памяти в Z.
Нет, ты можешь его из Z и не доставать. Но при этом у тебя Z становится регистром неприкосновенный (А точнее сразу оба регистра) и попытка что то туда записать черевата тем, что в прерывании твой уарт начнет срыгивать не твою строку, а вообще все что угодно. =)
Это понятно что сам факт использования региста Z, озночает что он неприкосновенный :). Понятно что стек используется для сброса данных. Это и освобождает тотже регистр Z и также полученные байты можно обработать позже. Но все равно получается что перед тем как принимать данные мы должны знать их точное количество (байты). Или же при каждом присланном байте отсылать байт потверждения о получении байта. Тогда можно наверно даже гигами пересылать без опаски потери какогото байта.
Это понятно что сам факт использования региста Z, озночает что он неприкосновенный :). Понятно что стек используется для сброса данных. Это и освобождает тотже регистр Z и также полученные байты можно обработать позже. Но все равно получается что перед тем как принимать данные мы должны знать их точное количество (байты). Или же при каждом присланном байте отсылать байт потверждения что байт обработан и сохранен. Тогда можно наверно даже гигами пересылать без опаски потери какогото байта.
Я тебе про передачу, а ты мне про прием.
При приеме мы пишем входящие данные в кольцевой буфер. И нам главное вовремя его обрабатывать. А знать сколько мы получим данных мы должны полюбому. По крайней мере чтобы понимать вообще что это нам идет. Впрочем, данные могут быть потоковыми и тогда главное вовремя их вынимать из кольцевого буфера и обрабатывать. Можно даже не складировать. Буфер позволит на время долгих операций подстраховаться, а уж выгрузить его дело недолгое.
Кстати функция вызванная прерыванием и функция вызваная программно могут работать параллельно(одновременно)? потому как если нет то обработка буфера займет может и небольшое но какоето время, пока летит 11-ый байт
Нет конечно. Проц то у нас один. Когда прерывание выполняется все остальное стоит. Поэтому то прерывания делают максимально короткими. Пришел байт? Заскочил, вытащил его из УДР регистра, кинул в буфер в память и выскочил обратно в фоновую программу. Пришел следующий байт? Вытащил, кинул в буфер и так далее.
Задача буфера продержать прием без потерь пока проц выполняет что то тяжелое (но редкое иначе у проца ваще времени не будет, а это уже косяк) и не может сразу обработать данные (например вычисляет чего или экран обновляет) зато потом у него будет время прожевать буфер ни на что другое не отвлекаясь.
Спасибо DI HALT
Возник следующий вопрос. Допустим отправлена от МК к МК строка , являющаяся некоей командой. Но дошла с искажением. Как представляется, слейв должен отправить мастеру об этом сообщение, а тот в ответ должен повторить команду. Вот и вопрос — как это правильно организуется? На приемной стороне понятно, а вот на отправляющей ведь нужно какое-то ожидание подтверждения правильности принятия посылки от слейва..
И еще. Сколько (минимально) байт должна содержать посылка, чтобы считать ее достаточно надежной. Имеется ввиду искажение в процессе передачи. Например, есть две команды » _A» и » _B». Если в процессе передачи вместо ‘А’ , случайно выскочит ‘B’, то получится нехорошо..
Не нужно ли запрещать прерывания, когда читаем данные из буфера приема? А то вдруг в момент чтения из буфера придет байт и не дочитав из буфера нужно будет ускакать на обработчик прерывания и записать в тот же буфер байт. Указатели записей начала и конца и флаги переполнения не крякнуться?
Из UDR то? Если сразу же забрать, то не успеет. Даже на максимальной скорости.
Да не, из закольцованнго буфера приема MAXBUFF_IN который находится в SRAME.
Вообще да, может. Лучше запрещать.
О! Может добавить в статью эту мыслишку.
Если ты не заметил, то уже :)
А!
а как быть если нужно чтобы по UART’у общалось несколько МК? как должны соединяться линии и как примерно должен выглядеть код?
Почитал статью и решил написать простенький класс уарта для плюсов, по мне, так как если есть стек, не люблю возиться с ОЗУ, а плюсы мне кажется gcc оптимизирует лучше, чем Си (размер всегда меньше у прошивок, лично у меня) Да и компактность, понятность кода лучше. Вот проект для AVR STUDIO 5.0 для attiny2313 http://file.qip.ru/file/wCDDOgNN/USART_simple.html (в 4 студии у меня что-то дебагер gcc не работает, извините), программа по запуску передаёт по уарту всю память флеш (заданы граничные адреса передачи), а потом пересылает принятые данные. В протеусе прошивка работает, в реальности ещё не пробывал. В протеусе класс обеспечивает полный дуплекс 38кбит на частоте камня 8МГц (при этом передачи работают в фоне и можно выполнять основную программу при этом), размер программы получился 600 байт, не знаю насколько это много. Вопрос вот в чём, есть ли умельцы кодинга, которые умеют оптимизировать код С++ ассемблерными вставками, думаю там можно сократить размер вдвое, если переписать прерывания (очень много идёт сохранений/восстановлений регистров). И если получится, отправьте на почту плиз результат, очень интересно узнать :) kefcresta(at)yandex.ru
Доброго времени суток .Частично «накопипастил» ,частично написал такую программу -
проблема в том что ..2 раза прерывание срабатывает по пустоте UDR.а потом прога тупо зацикливается и невходит в прерывание
.include «m32def.inc»
.list
.include «macro.inc»
.equ INPUT =0
.equ XTAL = 8000000
.equ baudrate = 9600
.equ bauddivider = XTAL/(8*baudrate)-1
.def Devais =R26
.def S =R0
.def inttemp =R1
.def ref1 =R2
.def ref2 =R3
.def temp =R16
.def date =R17
.def system =R19
.def command =R20
.def bitcnt =R21
.def signal =R18
.def tmp =R22
.def flag =R23
.def FCODE =R24 ;
;###################################################
.DSEG ;SRAM memory segment
;######################################################################
.CSEG ;begin of program memory
.org 0
;——————Прерывания ———————————
.ORG $000 ; (RESET)
RJMP start
.org $01C
RJMP uart_snt
.org $01A
RJMP uart_snt
.org $01E
RJMP uart_snt
;——————— Messages & Constants ———————————
DATA: .db 0xAA,0xAA,0xAA,0xAA
;———————— BEGIN OF PROGRAMM ———————————
. ; (INT0) External Interrupt Request 0
;———————- *** setup part *** ———————————
Start:
;—————————————————
;———————————————————
LDI R16,High(RAMEND)
OUT SPH,R16
LDI R16,Low(RAMEND) ; Инициализация стека
OUT SPL,R16 ; Обязательно!!!
.equ Byte = 50
.equ Delay = 20
;ldi r16,0xdf ;
;out SPL,r16 ;указатель стека
sbi ACME,ACD ;отключени компаратора О_о (разобраться с ASD)
ldi r16,0×00 ;
out DDRB,r16 ;DDRB «DDRB = 0xff»
ldi r16,0×00 ; «0″
out PORTB,r16 ;
ldi r16,0×00 ;
out DDRC,r16 ;
ldi r16,0×00 ; «0″
out PORTC,r16 ;
ldi r16,0×3 ; 11000000
out DDRD,r16 ;
ldi r16,0×00 ;
out PORTD,r16 ;
;————SPI инициализация ——————————————
ldi r16,0xD0 ;SPCR=0xD0; (0xC0 – ??? slave)
out SPCR,r16 ;
ldi r16,0×0 ;SPSR=0?0
out SPSR,r16 ;
;——————— USART ———————————-
LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE)
OUT UCSRB, R16
LDI R16, low(bauddivider)
OUT UBRRL,R16
LDI R16, high(bauddivider)
OUT UBRRH,R16
LDI R16,0
OUT UCSRA, R16
LDI R16, (1<<URSEL)|(1<<UCSZ0)|(1<MSB (Z)
ldi r30,0x1d ;Load 29=>LSB (Z)
RgClr: st Z,R31 ;0=>R(Z)
dec R30 ;Counter=counter-1 dec-??????????
brne RgClr ;Do until counter=0 Brne -??????? ???? ?? ?????
;———————- ????????? —————————————
sei ;разрешить прерывания глобально
loop :
ldi r16,’R’
mov date,r16
cpi date,1
BRGE m1 ;перейти если больше
Rcall loop
m1:
LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(1<<UDRIE)
OUT UCSRB, R16
nop
nop
nop
nop
rjmp loop
;—————Процедура отправки байта——————-
uart_snt:
PUSHF
SBIS UCSRA,UDRE ; Пропуск если нет флага готовности
RJMP uart_snt ; ждем готовности — флага UDRE
OUT UDR, date ; шлем байт
LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE)
OUT UCSRB, R16
ldi r16,0
; Возврат
POPF
RETi
не могу понять в чем проблема в Протеусе в терминал шлет какуюто ахинею
помогите плз=)
посмотри по таблице ASCII что означают твои данные….настройки терминала и самого контроллера. и регистры перепроверь….тоже проблема была не работал уарт, всю прогу перепроверил не работает…потом просто ещё раз регистры настройки уарта посмотрел и нашел ошибку)))
всем привет!!!помогите пожалуйста организовать прием по uart 2-х двухбайтных чисел и кода операции
посмотри выше….где то был такой уже пример)))
DI привет, совет твой нужен как спеца.
Вопрос_1:
Допустим в avr сыплются команды всего 8 команд. Каждая команда имеет пусть 10 символов (все условно). Но только на одну команду мне нужно ответить. Как лучше всего организовать отбор нашей нужной команды от остальных ненужных. Мне не нужен код, нужна просто идея, мысль как грамотно это сделать. Код я сам напишу. Может быть так — записать во флеш ту команду на которую надо ответить. Принимаемые же команды просто пишем в буфер, а когда считываем принятую команду из буфера сравниваем ее по CPI с командой из флеша, если какойто байт не совпал значит в ответ тишина. А если все байты совпали тогда принятая команда наша, тогда запускаем прерывание по UDR и выплевываем наш ответ?
Вопрос 2:
Нужно отвечать уже на все 8 команд. У каждой команды свои какие нибудь символы. Как команды отличать друг от друга? Каждую принятую команду сравнивать побайтно по CPI с восемью эталонами забитыми во флеш?
Проще так:
Нужное слово лежит в памяти или уже в регистрах, не важно.
Команду мы побайтно сверяем по XOR (можно и по CP) если не совпал хоть один из ожидаемого — пропускаем и ждем следующую пачку.
Тебе в любом случае придется побайтно сравнивать. Причем сразу же выбирать пути вариантов. Т.е. по мере ввода байтов у тебя сужается поле вариантов, на последнем байте остается только один. Проще всего это сделать пропуская через серию if
Спасибо! Буду реализовывать.
Всем Привет!
Возник следующий вопрос. Помогите пожалуйста кто может. Пытаюсь связать атмегу16 с телефоном Motorola E1000 через УАРТ. Проблема в том что телефон исполняет команды, но отклика не дает. Подключал по следующей схеме: http://img17.imageshack.us/i/indexpp.gif/
Распиновка разъема: http://img193.imageshack.us/i/indexln.gif/
Тактирую от внешнего кварца 11.0592 МГц, скорость передачи 9600.
PS: С меня пиво!
Уже разобрался.
привет всем. Подскажите как лучше сделать…есть программа, которая принимает и отсылает сообщения по уарту, у меня на макетке пока сделано просто: в обработчике прерывания на прием идет его обработка, читаю регистр UDR, сохраняю его значение в переменную и погнали дальше))дак вот суть вопроса есть много флагов типа прием завершен, регистр пуст, ошибки по передаче нет…как это всё можно по простому реализовать, т.е как написать в пару строк проверку этих флагов??желательно на Си. Заранее спасибо
либо же просто эти все регистры сразу проверять перед дальнейшей работой с сообщением которое пришло…
Добрый день. Среди комментариев не нашел аналогичной проблемы.
Программа, написанна на С в AVRStudio 4. Читаю данные и сразу отправляю обратно:
ISR(SIG_UART_RECV) {
U_Transmit(UDR);
}
В железе не работает :(
При отладке (использую simulation) устанавливаю бит RXC в UCSRA и значение UDR (в том числе внутри прерывания). При выполнении любой команды UDR обнуляется и, естественно, в функцию U_Transmit передается 0×00.
Подскажите в чем затык? Почему может UDR обнуляться.
Вот весь код:
#define F_CPU 8000000L
#include
#include
#define BDRATE 9600L
#define BDDIVIDER (F_CPU/(16*BDRATE)-1)
#define HI(x) ((x)>>8)
#define LO(x) ((x)&0xFF)
ISR(SIG_UART_RECV);
void initUART(void);
void U_Transmit(unsigned char);
int main(void)
{
volatile unsigned char i;
initUART();
sei(); // accept interrupt
while(1) {
i++;
}
return 0;
}
/*
* Interrupts
*/
/*
* USART RX
*/
ISR(SIG_UART_RECV) {
U_Transmit(UDR);
}
/*
* USART init
*/
inline void initUART() {
UBRRL = LO(BDDIVIDER);
UBRRH = HI(BDDIVIDER);
UCSRA = 0;
UCSRB = 1<<RXEN | 1<<TXEN | 1<<RXCIE | 0<<TXCIE; // accept rx & tx by USART, accept rx interrupt
UCSRC = 1<<URSEL | 1<<UCSZ0 | 1<<UCSZ1; //8bit + 1 stop + even parity
return;
}
// transmite byte by USART
void U_Transmit(unsigned char data) {
while(!(UCSRA & (1<<UDRE))) {
;
}
UCSRB &= ~(1<<TXB8);
if (data &0×100)
UCSRB |= (1<<TXB8);
UDR=data;
}
А попробуй отправлять обратно не в функции (она кстати лажовая, ибо использует цикл ожидания, а такие функции в прерывании юзать вообще жопа)
У тебя же по факту получается UDR = UDR.
Сделай в ISR просто:
i=UDR ;
UDR = i;
Разобрался:
1. Отладчик выдавал такой косяк из-за того что что проект хранился на сетевом диске. Положил проект в корень диска C: и сразу заработало. (походу, критичен не только путь установки компилятора, но и расположение самого проекта)
2. В железе не работало потому, что были установлены fuse биты, повлиявшие на частоту (изменил CKOPT и CKSELx). Не могу понять зачем они их на заводе выставляют.
PS
Может внесете изменения в статью «Программирование на Си» и укажете там что нужно еще fuse биты проверить?
2. Ну дык надо понимать на какой частоте работает контроллер. Изначально многие работают на низкой частоте. А FUSE к программированию мало относятся. Это скорей аппаратное обеспечение.
прошил мегу16, подключил… отрпавляю вайт возвращяеться не то что надо.. первые 6 бит правельны а последние 3 всегда то 101 то 111 чета не то.. настроил правельно пользуюсь терминалом v1.9b. до этого подлуючал GSM модуль всё замечательно работало.. может быть в монтаже??
Гдето со скоростью косяк. Либо скорость контроллера не та что ты думаешь. Мега 16 новая была? У ней по дефолту тактовая 1мгц.
Да новая поставил фьюзы на 8мгц..SCKDIV8 ведь там нету?
Делителя там нет. На косяк монтажа не похоже. Где то что то напутано. Может в коде. Бит u2X проверь, может его поставил/не поставил и изза этого проблемы со скоростью.
Всё перепробовал ничё не помогае.. буду искать..
Видимо не точный генератор стоит который встроенный. Поставил не 9600 а 9400 и заработалло..
В конце статьи было написано, что циклическая инициализация приводит к потери данных.
Это касается любых изменений в регистрах настройки UART или нет? Если например в прерывании по флагу RXC я разрешаю прерывание по флагу UDRE. Ну или вообще разрешаю или запрещаю прерывания по приему или передаче. Может ли это чисто теоретически привести к потерям?
у протеуса кстати UART симулирован неправильно — поначалу в нем хотел отладить -а он мне говорит- дескать неправильный опкод по такому то адресу, выходящему, вообще говоря, не то что за границы программы, но и вообще памяти МК — залил в реальный МК — все заработало как часы
Привет DI
бьюсь уже второй день над такой проблемой, задача очень простая, слать каждые 250мс в уарт один байт(0×48)
atmega16A-16 подключена к RT232RL (по схеме с этого сайта), дальше к компу через усб
на компе слушается виртуальный ком-порт
подключаю питание, землю, уарт на вход и выход, больше к контролеру ничего не подключено
слушаю порт, а там вместо 0×48 идет 0×88
причем если скажем послать c мк 0x7f приходит 0xbf
такое чувство что идет сдвиг вправо, только какой то странный
и тут самая магия, если отключить питание (+5v), то всё работает нормально(!)
непонятно откуда идёт питание, однако экспериментами удалось установить, что если отключить ножку уарта на приём, то контролер выключается, получается он как то берёт с неё питание, хотя в коде она вообще не используется
получается такой расклад
+5 подключено и ножка на приём подключена = неправильные данные
+5 подключено и ножка на приём не подключена = неправильные данные
+5 не подключено и ножка на приём подключена = всё работает корректно
+5 не подключено и ножка на приём не подключена = контролер не работает
это просто какая то жесть, как такое вообще возможно
из этого что я пытался сделать и не помогло
1) ресет подтягивал по питанию через 10ком резистор
2) менял скорости уарта
3) проверял переходник FT232RL путём замыкание приёмника и передатчика, работает отлично, данные возвращаются корректно
4) думал на глюки драйвера под линуксом, однако под вендой всё тоже самое
5) ставил фильтрующие конденсаторы на питание мк
6) добавлял в код перед инициалиазацией очистку памяти и регистров
7) ну и уже 10 раз всё перепроверил
еще интересный момент, когда дотрагиваешься пальцем до земли (при этом питание вообще не подключено, только уарт) то контролер стартует и передает вообще кашу в уарт, но это вообщем то логично
вот привожу код, простой как 3 копейки
http://easyelectronics.ru/repository.php?act=view&id=76
что делать? в чем причина такого поведения? может брак ft232 или контролера?
Проверь вначале FTDI и весь интерфейс. Коротни на ноге контроллера RX на TX и пошли что нибудь с компа, должно вернуться.
А у тебя похоже сильные срачи в питании. Раз на паразитном питании все ок, а с твоего питалова хрень.
да, FTDI проверял, замыкаю перемычкой TX и RX, пишу в порт байт, тут же возвращается, всё работает отлично
а питание берется с системного блока компьютера, 5 вольт, стоят конденсаторы в качестве фильтров, вроде как хорошее питание, компьютер то без проблем работает
есть еще какие то причины, что такая фигня вылазиет?
о, еще обнаружил такую фишку
с самого начала изучения МК я сделал себе платку с разьемом для атмеги и выводом всех его контактов на штыри, чтоб удобно было эксперементировать
так вот, сейчас отключил линию RX совсем от мк, так как данные идут только от мк
беру питание (+5), включаю терминал, мониторю интерфейс
втыкаю на Vcc, идут битые данные как и было
но стоит посадить питание (+5) на любую другую ножку, кроме GND и Vcc, то всё работает отлично, получается проблема не в плохом питании?
FTDI тоже норм работает, замыкаю rx и tx, отдаёт эхом, как и должно быть
сам переходник USB-UART делал по схеме с этого сайта
единственное сделал разводку на выводных элементов сам
вот, на всякий случай файл схемы ftp://luckystriker.net/usb_uart.lay
сам FT232 нормально припаялся, вроде нигде косяков нет
дальше тупо соединяется RX переходника и TX мк, ну и питание к мк, ресет подтягивается на 10кОм к +5, всё, больше ничего нет, питание к мк беру с переходника
впрочем, если брать питание с БП компа та же самая ситуация
что же делать? помоги пожалуйста
А контроллер на какой частоте работает?
1 MHz, настройки заводские, фуз биты не трогал
вот на всякие случай настройки фуз битов
fatalist@fatalist-laptop:~$ avrdude -c usbasp -p m16 -U hfuse:r:-:h -U lfuse:r:-:h
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.02s
avrdude: Device signature = 0x1e9403
avrdude: reading hfuse memory:
Reading | ################################################## | 100% 0.01s
avrdude: writing output file «»
0×99
avrdude: reading lfuse memory:
Reading | ################################################## | 100% 0.01s
avrdude: writing output file «»
0xe1
avrdude: safemode: Fuses OK
avrdude done. Thank you.
блин, щя покрутил частоту
8MHz — о чудо, всё работает нормально
4MHz — тоже всё работает
2MHz — работает
вернул на 1MHz — не работает блин
прочитал всю главу про USART в даташите, ничего про неработающий UART на 1 Мгц не сказано
в конце даже табличка для расчета UBBR на 1 мгц (с неё тоже пробовал напрямую забивать число)
блин, как так? на 1 мгц не работает уарт?
На малой скорости кварца надо юзать бит удвоения частоты уарта u2x
продолжаю мучить уарт, получил интересную зависимость
все результаты получены для частоты 1 мгц
снизив скорость уарта внезапно стало работать нормально
результаты:
2400 — работает
4800 — работает
9600 — не работает
ну и всё что выше не работает
в даташите сказано
For standard crystal and resonator frequencies, the most commonly used baud rates for
asynchronous operation can be generated by using the UBRR settings in Table 68.
UBRR values which yield an actual baud rate differing less than 0.5% from the target
baud rate, are bold in the table. Higher error ratings are acceptable, but the receiver will
have less noise resistance when the error ratings are high, especially for large serial
frames
это таблица из даташита, скорость и процент ошибок, частота мк 1 мгц
2400 25 0.2%
4800 12 0.2%
9600 6 -7.0%
14.4k 3 8.5%
19.2k 2 8.5%
28.8k 1 8.5%
38.4k 1 -18.6%
57.6k 0 8.5%
Вот где собака зарыта!
сигнал сдвинут и стробы стробирующего приёмника не попадают на импульс, поэтому получается такой странный «сдвиг» о котором я говорил в самом начале
буквально пару дней назад защищал лабу в универе на эту тему, ппц, надо было ходить на лекции!
это конечно мои догадки, как устроен приёмник уарта я не знаю, как думаешь DI, в этом проблема?
вот такой неочевидный нюанс
может стоит добавить это в статью?
остается правда еще вопрос, почему при паразитном питании всё работает нормально?
Если в обработчике Tx Complete писать в UDR возникнет ли зацикливание? Можно это использовать?
Возникнет. Можно.
а можно код сего прекрасного буфера в качестве либы на Си?
чтобы также на прерываниях и вх. и вых. буфера
Когда нибудь, может через годик…
что то прием идет не так как надо по UARTу. Использую Atmega8515, отлаживаю на STK500.
задача: мк принимает данные и в двоичном коде показывает их на восьми светодиодах. Данные посылаю через програмку «Terminal v1.9b». число вроде отображает, но на PB4 всегда лог.1, то есть
посыл «1″ должен показать 00000001 но показывает 00010001
посыл «2″ должен показать 00000010 но показывает 00010010 и так далее..
обработчик прерывания простейший:
PriemZavershen:
in r16,UDR
out PortB,r16
reti
DI HALT,подскажи плиз почему у тебя в команде out пишется названия порта ,а у меня студия на это ругается,а вот как ввнизу я написал все норм.И еще не могу поставить нумерацию строк))
.equ XTAL = 8000000
.equ baudrate = 9600
.equ bauddivider = XTAL/(16*baudrate)-1
uart_init: LDI R16,low(bauddivider)
OUT 9,R16
Ругаться может по двум причинам:
1) не подключен файл с символьными определениями (inc файл)
2) данный порт выходит за границы действия команды OUT и обращение к нему идет через LD/ST (часто встречается на новых мк, аля мега168)
Точно, я не подключал библеотеку. спасибо
еще вопрос. Как сделать чтоб студия не ругалась на конец кода и не происходил сброс.
а как она ругается и от чего происходит сброс? И как выглядит конец кода?
так выглядит код, не не че не сбрасывается)) просто ошибку показывает
.include «tn2313def.inc»;
.equ XTAL = 8000000;
.equ baudrate = 9600;
.equ bauddivider = XTAL/(16*baudrate)-1
uart_init: LDI R16,low(bauddivider)
OUT ubrrl,R16
LDI R16,high(bauddivider)
out ubrrh,r16
AVR Simulator: Invalid opcode 0xffff at address 0×000004
Код обрывать нельзя. У тебя после конца нет ничего, процессор суется в память, а там пусто. Непрошитые ячейки. Надо зацикливать программу либо в главный цикл (в начало) либо на одну команду —
Metka: RJMP Metka ; Прога зациклится тут навсегда.
Или так. Сам догадайся как это работает ;)
RJMP PC
это безусловный переход туда куда показывает программный указатель.Но регистр UDRE при этом всеровно ставится в 1, почему?
хотя да все правильно буфер UDR готов принять данные он пуст,но когда проц его успевает опросить он же зациклен. Или это прерываения?
все разобрался это прерывание. тут их еще2 есть)))
ДИ ХАЛТ, привет, помоги, не могу разобратся с этим куском кода:
.include «tn2313def.inc»
.equ XTAL = 8000000
.equ baudrate = 9600
.equ bauddivider = XTAL/(16*baudrate)-1
uart_init: LDI R16, low(bauddivider)
OUT 0×09,R16
LDI R16,high(bauddivider)
OUT 0×02,R16
ldi r16,0×00
out 0x0b,r16
ldi r16,0×90
out 0x0a,r16
ldi r16,0×06
out 0×03,r16
при отправки байта в регистор UCRSC байт почему то летит в регистор UBRRH. И я не чего не могу с этим поделать. Мож это связанно с тем что я поставил семерку 64, на семерке 86 помоему все было норм. Пишу в авр студии 19 версии.Мож другую прогу посаветуеш под семерку 64. Спасибо.
Даташит читать надо. У некоторых аврок регистры уббрх и укцрс находятся на одном адресе, а для выбора куда слать есть бит URSEL или как то так. Вот если его поставить полетит в одну сторону, сбросить — в другую. Читай описание регистров уарта.
конечно я прочитал весь дататиш про регистры тини 2313,прежде чем задать вопрос.Мож я не правилно сказал, при обращении к регистру ucsrc биты меняются и в нем и в регистре задания скорости ubrrh(биты 0,1,2,3).
студия вполне может и глючить. Проверяйте в железе.
Извините пожалуйста, а почему пропали все коментарии? у меня ни что не отображается!?! напишите пожалуйста мне на почту ( slavik.ksu@mail.ru) в чем может быть проблема?
Здравствуй, DI HALT, подскажи, есть ли возможность организовать связь по последовательному порту между несколькими МК (без участия компьютера), что-то вроде общей шины.
Заранее извиняюсь, если вопрос глупый, у меня совсем нет опыта).Задача вроде бы тривиальная, несколько МК, один из них (мастер) непрерывно рассылает соообщения на остальные(слейвы), а также постоянно принимает сообщения от них же. Слейвы между собой не обмениваются.
Что лучше использовать для такой схемы? I2C, SPI, еще что-нибудь?
P.S. Насчет использования I2C не уверен, т.к. один из слейвов будет постоянно опрашивать по I2C датчик, тем самым постоянно занимая шину.
1. Есть. У UART есть мультиточечный режим. НЕ помню как называется, но что то такое есть. Не юзал, Читайте доки.
2. Если длинна шины не превышает десятков сантиметров, то лучше I2C. По скорости вам наверняка хватит с лихвой (до 400кбит вроде бы). Если линия длинная, то CAN.
SPI возможно, но там потребуется по enable линии к какждому из слейвов и оно также не предназначено для длинных линий. Только в пределах платы/устройства.
Спасибо за ответ!
Подскажи еще, возможно ли такое соединение по последовательному протоколу между датчиком-передатчиком и двумя контроллерами приемниками? Причем без участия промежуточных интерфейсов типа RS-485, а напрямую, по TTL-уровням (или даже Low voltage TTL) ?
Иллюстрацию забыл)
http://imageshack.us/photo/my-images/194/serialh.png/
Т.е. с одного TX слать на два RX? Это без проблем. RX это же просто Hi-Z вход. Хоть на десяток. Ну разве что после второго десятка емкость суммарная будет уже влиять.
Это очень хорошо. Спасибо)
Привет DI. Хотел спросить,
1.Ты сейчас вообще занимаешься AVR-ками или уже как бы это так постольку поскольку?
2.Если мы cчитали байт из регистра UDR в обработчике, то сам udr обнуляется или данные в нем еще есть и их еще раз можно считать уже в другой регистр?
1. Это мой основной контроллер. ARM я лениво изучаю, но делать свои проекты предпочитаю на AVR.
2. Точно не помню, точно знаю, что при чтении снимается флаг прерывания.
День добрый! Есть прога в AVR, которая должна передавать данные по UART для ATTiny 167. Вопрос следующий: почему при выполнениии LTXOK всегда остается равным 0? (LTXOK = 1, означает, что Tx Response complete) Почему передача так и проходит?
#include
#include
#include
#define XTAL 8000000
#define SAMPLES_PER_BIT 8
#define baudrate 9600
#define bauddivider (XTAL/(16*baudrate)-1)
#define HI(x) ((x)>>8)
#define LO(x) ((x)& 0xFF)
void SetupUart(void);
void TxUart(unsigned char data);
void SetupUart(void) //Configure LIN UART in UART mode — full dulex
{
LINBRRL = LO(bauddivider);
LINBRRH = HI(bauddivider);
DDRA = 0×02; //(RX is PA0, TX is PA1)
LINCR = (1 << LENA)| (1 << LCMD0) | (1 << LCMD1) | (1 << LCMD2);
// Set samples per bit and UART baud
// LINBTR = (1 << LDISR) | SAMPLES_PER_BIT;
// LINBRR = ((XTAL / SAMPLES_PER_BIT) / baudrate) — 1;
}
int main (void)
{
SetupUart();
///////transmit
unsigned char Test=155;
SREG |= (1 << 7); // Enable interrupts
LINENIR =(1<<LENTXOK); // Enable transmit
TxUart(Test);
}
void TxUart(unsigned char data)
{
LINDAT = data;
while ((LINSIR & (1 << LTXOK))); //until Transmit is Performed
}
ISR (LIN_TC_vect)
{
int i = 1;
i++;
}
Здравствуйте. Проблема такая.
В процессе обучения решил попробовать сделать так:
Зажигать светодиод подключенный к PC0 при приходе любого байта на UART
http://easyelectronics.ru/repository.php?act=view&id=90
Шлю байты, шлю, а прерывание он не вызывает. В чём может быть причина?
Прерывания глобально не разрешил. Добавь после инита уарта команду SEI